Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
/tests export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.scrutinizer.yml export-ignore
/.travis.yml export-ignore
/phpunit.xml.dist export-ignore
/README.md export-ignore
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Tests

on:
push:
pull_request:

jobs:
tests:
name: "Tests"
runs-on: ubuntu-latest

strategy:
matrix:
php-version: ['8.1', '8.2', '8.3', '8.4']
include:
- { php-version: '8.1', dependencies: '--prefer-lowest' }

steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
coverage: xdebug

- name: Install PHP dependencies
run: composer update --no-interaction ${{ matrix.dependencies }}

- name: Run tests
run: vendor/bin/phpunit

- name: Run PHPStan
run: vendor/bin/phpstan
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.idea/
.phpunit.cache/
vendor/
composer.lock
composer.lock
5 changes: 0 additions & 5 deletions .scrutinizer.yml

This file was deleted.

24 changes: 0 additions & 24 deletions .travis.yml

This file was deleted.

7 changes: 2 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
VATIN
=====
[![Build Status](https://travis-ci.org/ddeboer/vatin.svg?branch=master)](https://travis-ci.org/ddeboer/vatin)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ddeboer/vatin/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/ddeboer/vatin/?branch=master)
[![Code Coverage](https://scrutinizer-ci.com/g/ddeboer/vatin/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/ddeboer/vatin/?branch=master)
[![Latest Stable Version](https://poser.pugx.org/ddeboer/vatin/v/stable.png)](https://packagist.org/packages/ddeboer/vatin)

A small PHP library for validating VAT identification numbers (VATINs).
Expand All @@ -27,7 +24,7 @@ Validate a VAT number’s format:
```php
use Ddeboer\Vatin\Validator;

$validator = new Validator;
$validator = new Validator();
$bool = $validator->isValid('NL123456789B01');
```

Expand All @@ -37,6 +34,6 @@ Information Exchange System (VIES)](https://ec.europa.eu/taxation_customs/vies/f
```php
use Ddeboer\Vatin\Validator;

$validator = new Validator;
$validator = new Validator();
$bool = $validator->isValid('NL123456789B01', true);
```
13 changes: 11 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@
}
],
"require": {
"php": ">=5.6.0"
"php": ">=8.1"
},
"require-dev": {
"ext-soap": "*",
"phpunit/phpunit": "^5.7 || ^6.5"
"phpstan/phpstan": "^2.1",
"phpstan/phpstan-phpunit": "^2.0",
"phpstan/phpstan-symfony": "^2.0",
"phpstan/extension-installer": "^1.4",
"phpunit/phpunit": "^10.5"
},
"suggest": {
"ext-soap": "Required if you want to check the VAT number via VIES"
Expand All @@ -33,5 +37,10 @@
"psr-4": {
"Ddeboer\\Vatin\\Test\\": "tests/"
}
},
"config": {
"allow-plugins": {
"phpstan/extension-installer": true
}
}
}
19 changes: 19 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
parameters:
ignoreErrors:
-
message: '#^Method Ddeboer\\Vatin\\Vies\\Client\:\:checkVat\(\) should return Ddeboer\\Vatin\\Vies\\Response\\CheckVatResponse but returns mixed\.$#'
identifier: return.type
count: 1
path: src/Vies/Client.php

-
message: '#^Readonly property Ddeboer\\Vatin\\Vies\\Response\\CheckVatResponse\:\:\$date is assigned outside of the constructor\.$#'
identifier: property.readOnlyAssignNotInConstructor
count: 1
path: src/Vies/Response/CheckVatResponse.php

-
message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\) with ''DateTimeImmutable'' and DateTimeImmutable will always evaluate to true\.$#'
identifier: method.alreadyNarrowedType
count: 1
path: tests/Vies/ClientTest.php
8 changes: 8 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
includes:
- phpstan-baseline.neon

parameters:
level: max
paths:
- src
- tests
29 changes: 21 additions & 8 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>

<phpunit bootstrap="vendor/autoload.php" colors="true">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
cacheDirectory=".phpunit.cache"
failOnEmptyTestSuite="true"
failOnIncomplete="true"
failOnRisky="true"
failOnSkipped="true"
displayDetailsOnIncompleteTests="true"
displayDetailsOnSkippedTests="true"
displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnTestsThatTriggerErrors="true"
displayDetailsOnTestsThatTriggerNotices="true"
displayDetailsOnTestsThatTriggerWarnings="true"
>
<testsuites>
<testsuite name="Ddeboer Vatin Test Suite">
<directory suffix="Test.php">./tests/</directory>
</testsuite>
</testsuites>

<filter>
<whitelist>
<directory suffix=".php">./src</directory>
</whitelist>
</filter>
</phpunit>
<source>
<include>
<directory>./src</directory>
</include>
</source>
</phpunit>
13 changes: 13 additions & 0 deletions src/Exception/ServiceUnreachableException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types = 1);

namespace Ddeboer\Vatin\Exception;

class ServiceUnreachableException extends \RuntimeException implements ViesExceptionInterface
{
public function __construct(?\Throwable $previous = null)
{
parent::__construct('VIES service unreachable', previous: $previous);
}
}
7 changes: 5 additions & 2 deletions src/Exception/ViesException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

namespace Ddeboer\Vatin\Exception;

class ViesException extends \RuntimeException
class ViesException extends \RuntimeException implements ViesExceptionInterface
{

public function __construct(?\Throwable $previous = null)
{
parent::__construct('Error communicating with VIES service', previous: $previous);
}
}
7 changes: 7 additions & 0 deletions src/Exception/ViesExceptionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Ddeboer\Vatin\Exception;

interface ViesExceptionInterface extends \Throwable
{
}
69 changes: 16 additions & 53 deletions src/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Ddeboer\Vatin;

use Ddeboer\Vatin\Vies\Client;
use Ddeboer\Vatin\Exception\ViesException;
use Ddeboer\Vatin\Vies\ClientInterface;

/**
* Validate a VAT identification number (VATIN)
Expand All @@ -12,15 +12,15 @@
* @link http://sima.cat/nif.php
* @link https://github.com/jonathanmaron/zf2_proposal/blob/master/library/Zend/Validator/Vatin.php
*/
class Validator
final class Validator implements ValidatorInterface
{
/**
* Regular expression patterns per country code
*
* @var array
* @var array<string, string>
* @link http://ec.europa.eu/taxation_customs/vies/faq.html?locale=lt#item_11
*/
private $patterns = array(
private const PATTERNS = [
'AT' => 'U[A-Z\d]{8}',
'BE' => '[01]{1}\d{9}',
'BG' => '\d{9,10}',
Expand Down Expand Up @@ -52,38 +52,19 @@ class Validator
'SI' => '\d{8}',
'SK' => '\d{10}',
'XI' => '\d{9,12}|(GD|HA)\d{3}'
);

/**
* Client for the VIES web service
*
* @var Client
*/
private $viesClient;
];

/**
* Constructor
*
* @param Client|null $viesClient Client for the VIES web service
* @param ClientInterface $viesClient Client for the VIES web service
*/
public function __construct(Client $viesClient = null)
{
$this->viesClient = $viesClient;
public function __construct(
private readonly ClientInterface $viesClient = new Client()
) {
}

/**
* Returns true if value is a valid VAT identification number, false
* otherwise
*
* @param string $value Value
* @param bool $checkExistence In addition to checking the VATIN's format
* for validity, also check whether the VATIN
* exists. This requires a call to the VIES
* web service.
*
* @return bool
*/
public function isValid($value, $checkExistence = false)
public function isValid(?string $value, bool $checkExistence = false): bool
{
if (null === $value || '' === $value) {
return false;
Expand All @@ -96,42 +77,24 @@ public function isValid($value, $checkExistence = false)
return false;
}

if (0 === preg_match('/^(?:'.$this->patterns[$countryCode].')$/', $vatin)) {
if (0 === preg_match('/^(?:'.self::PATTERNS[$countryCode].')$/', $vatin)) {
return false;
}

if (true === $checkExistence) {
$result = $this->getViesClient()->checkVat($countryCode, $vatin);
$result = $this->viesClient->checkVat($countryCode, $vatin);

return $result->isValid();
return $result->valid;
}

return true;
}

/**
* Returns true if value is valid country code, false otherwise
*
* @param string $value Value
*
* @return bool
* @return bool true if value is valid country code, false otherwise
*/
private function isValidCountryCode($value)
private function isValidCountryCode(string $value): bool
{
return isset($this->patterns[$value]);
}

/**
* Get VIES client
*
* @return Client
*/
private function getViesClient()
{
if ($this->viesClient === null) {
$this->viesClient = new Client();
}

return $this->viesClient;
return isset(self::PATTERNS[$value]);
}
}
19 changes: 19 additions & 0 deletions src/ValidatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types = 1);

namespace Ddeboer\Vatin;

interface ValidatorInterface
{
/**
* Returns true if value is a valid VAT identification number, false
* otherwise.
*
* @param bool $checkExistence In addition to checking the VATIN's format
* for validity, also check whether the VATIN
* exists. This requires a call to the VIES web
* service.
*/
public function isValid(?string $value, bool $checkExistence = false): bool;
}
Loading