diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..b86e521 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,23 @@ +name: Tests +on: [ pull_request ] + +jobs: + unit: + name: PHPUnit + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.4 + coverage: none + + - name: Download dependencies + uses: ramsey/composer-install@v2 + + - name: PHPUnit (unit tests) + run: ./vendor/bin/phpunit diff --git a/README.md b/README.md index 4817be1..39787f5 100644 --- a/README.md +++ b/README.md @@ -12,32 +12,15 @@ Via Composer $ composer require jongotlin/identity-number-bundle ``` -```php -class AppKernel extends Kernel -{ - public function registerBundles() - { - $bundles = array( - // ... - new JGI\IdentityNumberValidatorBundle\IdentityNumberValidatorBundle(), - } - } -} -``` - ## Usage ```php use JGI\IdentityNumberValidatorBundle\Validator\Constraints as IdentityNumberAssert; -/** - * @IdentityNumberAssert\IdentityNumber(allowCoordinationNumber=true) - */ -private $identityNumber; +#[IdentityNumberAssert\IdentityNumber(allowCoordinationNumber=true)] +private ?string $identityNumber; -/** - * @IdentityNumberAssert\OrganizationNumber(allowPersonalIdNumber=true, allowCoordinationNumber=true) - */ -private $organizationNumber; +#[IdentityNumberAssert\OrganizationNumber(allowPersonalIdNumber=true, allowCoordinationNumber=true)] +private ?string $organizationNumber; ``` Available options are diff --git a/composer.json b/composer.json index 9cdc54e..599e093 100644 --- a/composer.json +++ b/composer.json @@ -19,12 +19,12 @@ } }, "require": { - "php": "^7.0|^8.0", - "symfony/framework-bundle": "^2.7|^3.0|^4.0|^5.0|^6.0", - "byrokrat/id": "^1.0" + "php": "^8.2", + "symfony/framework-bundle": "^7.0|^8.0", + "byrokrat/id": "^2.1" }, "require-dev": { - "phpunit/phpunit": "^9.5", - "symfony/validator": "^6.0" + "phpunit/phpunit": "^12.5", + "symfony/validator": "^8.0" } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 73d3304..58359ea 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,7 +13,7 @@ - Tests + tests diff --git a/src/DependencyInjection/IdentityNumberValidatorExtension.php b/src/DependencyInjection/IdentityNumberValidatorExtension.php index 612e68f..b7058a8 100644 --- a/src/DependencyInjection/IdentityNumberValidatorExtension.php +++ b/src/DependencyInjection/IdentityNumberValidatorExtension.php @@ -4,7 +4,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Config\FileLocator; -use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader; class IdentityNumberValidatorExtension extends Extension @@ -12,7 +12,7 @@ class IdentityNumberValidatorExtension extends Extension /** * {@inheritdoc} */ - public function load(array $config, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); diff --git a/src/Validator/Constraints/IdentityNumber.php b/src/Validator/Constraints/IdentityNumber.php index c3b1bbb..8bf10ff 100644 --- a/src/Validator/Constraints/IdentityNumber.php +++ b/src/Validator/Constraints/IdentityNumber.php @@ -4,35 +4,26 @@ use Symfony\Component\Validator\Constraint; -/** - * @Annotation - */ +#[\Attribute] class IdentityNumber extends Constraint { - /** - * @var string - */ - public $message = 'This value is not a valid identity number.'; - - /** - * @var string - */ - public $messageWithCoordinationNumber = 'This value is not a valid identity number or coordination number.'; - - /** - * @var bool - */ - public $allowCoordinationNumber = false; - - /** - * @var bool - */ - public $strict = false; - - /** - * @return string - */ - public function validatedBy() + public string $message = 'This value is not a valid identity number.'; + + public string $messageWithCoordinationNumber = 'This value is not a valid identity number or coordination number.'; + + public bool $allowCoordinationNumber = false; + + public bool $strict = false; + + public function __construct(?string $message = null, ?string $messageWithCoordinationNumber = null, ?bool $allowCoordinationNumber = null, ?bool $strict = null) + { + $this->message = $message ?? $this->message; + $this->messageWithCoordinationNumber = $messageWithCoordinationNumber ?? $this->messageWithCoordinationNumber; + $this->allowCoordinationNumber = $allowCoordinationNumber ?? $this->allowCoordinationNumber; + $this->strict = $strict ?? $this->strict; + } + + public function validatedBy(): string { return 'jgi.validator.identity_number'; } diff --git a/src/Validator/Constraints/IdentityNumberValidator.php b/src/Validator/Constraints/IdentityNumberValidator.php index df2d879..23356d1 100644 --- a/src/Validator/Constraints/IdentityNumberValidator.php +++ b/src/Validator/Constraints/IdentityNumberValidator.php @@ -7,37 +7,22 @@ use byrokrat\id\PersonalIdFactory; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; class IdentityNumberValidator extends ConstraintValidator { - /** - * @var PersonalIdFactory - */ - protected $personalIdFactory; - - /** - * @var CoordinationIdFactory - */ - protected $coordinationIdFactory; - - /** - * @param PersonalIdFactory $personalIdFactory - * @param CoordinationIdFactory $coordinationIdFactory - */ - public function __construct(PersonalIdFactory $personalIdFactory, CoordinationIdFactory $coordinationIdFactory) - { - $this->personalIdFactory = $personalIdFactory; - $this->coordinationIdFactory = $coordinationIdFactory; + public function __construct( + private readonly PersonalIdFactory $personalIdFactory, + private readonly CoordinationIdFactory $coordinationIdFactory + ) { } - /** - * @param mixed $value - * @param Constraint|IdentityNumber $constraint - * - * @return void - */ - public function validate($value, Constraint $constraint) + public function validate(mixed $value, Constraint $constraint): void { + if (!$constraint instanceof IdentityNumber) { + throw new UnexpectedTypeException($constraint, IdentityNumber::class); + } + if (null === $value || '' === $value) { return; } diff --git a/src/Validator/Constraints/OrganizationNumber.php b/src/Validator/Constraints/OrganizationNumber.php index 6a66499..7fd7d54 100644 --- a/src/Validator/Constraints/OrganizationNumber.php +++ b/src/Validator/Constraints/OrganizationNumber.php @@ -4,35 +4,26 @@ use Symfony\Component\Validator\Constraint; -/** - * @Annotation - */ +#[\Attribute] class OrganizationNumber extends Constraint { - /** - * @var string - */ - public $message = 'This value is not a valid organization number.'; - - /** - * @var bool - */ - public $strict = false; - - /** - * @var bool - */ - public $allowPersonalIdNumber = false; - - /** - * @var bool - */ - public $allowCoordinationNumber = false; - - /** - * @return string - */ - public function validatedBy() + public string $message = 'This value is not a valid organization number.'; + + public bool $strict = false; + + public bool $allowPersonalIdNumber = false; + + public bool $allowCoordinationNumber = false; + + public function __construct(?string $message = null, ?bool $strict = null, ?bool $allowPersonalIdNumber = null, ?bool $allowCoordinationNumber = null) + { + $this->message = $message ?? $this->message; + $this->strict = $strict ?? $this->strict; + $this->allowPersonalIdNumber = $allowPersonalIdNumber ?? $this->allowPersonalIdNumber; + $this->allowCoordinationNumber = $allowCoordinationNumber ?? $this->allowCoordinationNumber; + } + + public function validatedBy(): string { return 'jgi.validator.organization_number'; } diff --git a/src/Validator/Constraints/OrganizationNumberValidator.php b/src/Validator/Constraints/OrganizationNumberValidator.php index e7c5787..17b16f2 100644 --- a/src/Validator/Constraints/OrganizationNumberValidator.php +++ b/src/Validator/Constraints/OrganizationNumberValidator.php @@ -8,46 +8,23 @@ use byrokrat\id\PersonalIdFactory; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; class OrganizationNumberValidator extends ConstraintValidator { - /** - * @var OrganizationIdFactory - */ - protected $organizationIdFactory; - - /** - * @var PersonalIdFactory|null - */ - protected $personalIdFactory; - - /** - * @var CoordinationIdFactory|null - */ - protected $coordinationIdFactory; - - /** - * @param OrganizationIdFactory $factory - */ public function __construct( - OrganizationIdFactory $organizationIdFactory, - PersonalIdFactory $personalIdFactory = null, - CoordinationIdFactory $coordinationIdFactory = null - ) - { - $this->organizationIdFactory = $organizationIdFactory; - $this->personalIdFactory = $personalIdFactory; - $this->coordinationIdFactory = $coordinationIdFactory; + private readonly OrganizationIdFactory $organizationIdFactory, + private readonly ?PersonalIdFactory $personalIdFactory = null, + private readonly ?CoordinationIdFactory $coordinationIdFactory = null + ) { } - /** - * @param mixed $value - * @param Constraint|OrganizationNumber $constraint - * - * @return void - */ - public function validate($value, Constraint $constraint) + public function validate($value, Constraint $constraint): void { + if (!$constraint instanceof OrganizationNumber) { + throw new UnexpectedTypeException($constraint, OrganizationNumber::class); + } + if (null === $value || '' === $value) { return; } diff --git a/tests/Validator/Constraints/IdentityNumberValidatorTest.php b/tests/Validator/Constraints/IdentityNumberValidatorTest.php index b1343ea..4c6e124 100644 --- a/tests/Validator/Constraints/IdentityNumberValidatorTest.php +++ b/tests/Validator/Constraints/IdentityNumberValidatorTest.php @@ -6,15 +6,14 @@ use byrokrat\id\PersonalIdFactory; use JGI\IdentityNumberValidatorBundle\Validator\Constraints\IdentityNumber; use JGI\IdentityNumberValidatorBundle\Validator\Constraints\IdentityNumberValidator; +use PHPUnit\Framework\Attributes\Test; +use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; use byrokrat\id\Exception; class IdentityNumberValidatorTest extends ConstraintValidatorTestCase { - /** - * @return IdentityNumberValidator - */ - protected function createValidator() + protected function createValidator(): ConstraintValidatorInterface { return new IdentityNumberValidator( $this->createMock(PersonalIdFactory::class), @@ -22,18 +21,14 @@ protected function createValidator() ); } - /** - * @test - */ + #[Test] public function socialSecurityNumberIsValid() { $this->validator->validate('-', new IdentityNumber()); $this->assertNoViolation(); } - /** - * @test - */ + #[Test] public function invalidSocialSecurityNumberIsInvalid() { $personalIdFactoryMock = $this->createMock(PersonalIdFactory::class); @@ -52,9 +47,7 @@ public function invalidSocialSecurityNumberIsInvalid() ; } - /** - * @test - */ + #[Test] public function invalidCoordinationNumberIsInvalid() { $personalIdFactoryMock = $this->createMock(PersonalIdFactory::class); @@ -69,25 +62,21 @@ public function invalidCoordinationNumberIsInvalid() ); $this->validator->initialize($this->context); - $this->validator->validate('-', new IdentityNumber(['allowCoordinationNumber' => true])); + $this->validator->validate('-', new IdentityNumber(allowCoordinationNumber: true)); $this ->buildViolation('This value is not a valid identity number or coordination number.') ->assertRaised() ; } - /** - * @test - */ + #[Test] public function coordinationNumberIsValid() { - $this->validator->validate('-', new IdentityNumber(['allowCoordinationNumber' => true])); + $this->validator->validate('-', new IdentityNumber(allowCoordinationNumber: true)); $this->assertNoViolation(); } - /** - * @test - */ + #[Test] public function coordinationNumberWithoutAllowConfigIsInvalid() { $personalIdFactoryMock = $this->createMock(PersonalIdFactory::class); @@ -108,9 +97,7 @@ public function coordinationNumberWithoutAllowConfigIsInvalid() ; } - /** - * @test - */ + #[Test] public function strictSocialSecurityNumberIsValid() { $this->validator = new IdentityNumberValidator( @@ -119,13 +106,11 @@ public function strictSocialSecurityNumberIsValid() ); $this->validator->initialize($this->context); - $this->validator->validate('195605158616', new IdentityNumber(['strict' => true])); + $this->validator->validate('195605158616', new IdentityNumber(strict: true)); $this->assertNoViolation(); } - /** - * @test - */ + #[Test] public function nonStrictSocialSecurityNumberIsInvalid() { $this->validator = new IdentityNumberValidator( @@ -134,7 +119,7 @@ public function nonStrictSocialSecurityNumberIsInvalid() ); $this->validator->initialize($this->context); - $this->validator->validate('560515-8616', new IdentityNumber(['strict' => true])); + $this->validator->validate('560515-8616', new IdentityNumber(strict: true)); $this ->buildViolation('This value is not a valid identity number.') ->assertRaised() diff --git a/tests/Validator/Constraints/OrganizationNumberValidatorTest.php b/tests/Validator/Constraints/OrganizationNumberValidatorTest.php index af5091b..0366e03 100644 --- a/tests/Validator/Constraints/OrganizationNumberValidatorTest.php +++ b/tests/Validator/Constraints/OrganizationNumberValidatorTest.php @@ -5,31 +5,26 @@ use byrokrat\id\OrganizationIdFactory; use JGI\IdentityNumberValidatorBundle\Validator\Constraints\OrganizationNumber; use JGI\IdentityNumberValidatorBundle\Validator\Constraints\OrganizationNumberValidator; +use PHPUnit\Framework\Attributes\Test; +use Symfony\Component\Validator\ConstraintValidatorInterface; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; use byrokrat\id\Exception; class OrganizationNumberValidatorTest extends ConstraintValidatorTestCase { - /** - * @return OrganizationNumberValidator - */ - protected function createValidator() + protected function createValidator(): ConstraintValidatorInterface { return new OrganizationNumberValidator($this->createMock(OrganizationIdFactory::class)); } - /** - * @test - */ + #[Test] public function organizationNumberIsValid() { $this->validator->validate('-', new OrganizationNumber()); $this->assertNoViolation(); } - /** - * @test - */ + #[Test] public function invalidOrganizationNumberIsInvalid() { $organizationIdFactoryMock = $this->createMock(OrganizationIdFactory::class); @@ -45,27 +40,23 @@ public function invalidOrganizationNumberIsInvalid() ; } - /** - * @test - */ + #[Test] public function strictOrganizationNumberIsValid() { $this->validator = new OrganizationNumberValidator($this->createMock(OrganizationIdFactory::class)); $this->validator->initialize($this->context); - $this->validator->validate('5569209900', new OrganizationNumber(['strict' => true])); + $this->validator->validate('5569209900', new OrganizationNumber(strict: true)); $this->assertNoViolation(); } - /** - * @test - */ + #[Test] public function nonStrictOrganizationNumberIsInvalid() { $this->validator = new OrganizationNumberValidator($this->createMock(OrganizationIdFactory::class)); $this->validator->initialize($this->context); - $this->validator->validate('556920-9900', new OrganizationNumber(['strict' => true])); + $this->validator->validate('556920-9900', new OrganizationNumber(strict: true)); $this ->buildViolation('This value is not a valid organization number.') ->assertRaised()