Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
EUVat
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 1
 isValid
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Validation\Finance
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Validation\Finance;
16
17use phpOMS\Validation\ValidatorAbstract;
18
19/**
20 * Very basic but **incomplete** VAT validation.
21 *
22 * For a proper VAT validation use existing APIs.
23 *
24 * @package phpOMS\Validation\Finance
25 * @license OMS License 2.0
26 * @link    https://jingga.app
27 * @since   1.0.0
28 */
29final class EUVat extends ValidatorAbstract
30{
31    public const PATTERNS = [
32        'EUROPE' => '/^(EU)([0-9][9])$/', // This is a special EU VAT.
33        'AUT'    => '/^(AT)U[0-9]{8}$/',
34        'BEL'    => '/^(BE)[0-9]{10}$/',
35        'BGR'    => '/^(BG)[0-9]{9,10}$/',
36        'CYP'    => '/^(CY)[0-9]{8}[A-Z]$/',
37        'CZE'    => '/^(CZ)([0-9]{8,10}|[0-9]{6}-[0-9]{3,4})$/',
38        'DEU'    => '/^(DE)[0-9]{9}$/',
39        'DNK'    => '/^(DK)[0-9]{8}$/',
40        'EST'    => '/^(EE)[0-9]{9}$/',
41        'ESP'    => '/^(ES)([A-Z][0-9]{8}|[A-Z][0-9]{7}[A-Z])$/',
42        'FIN'    => '/^(FI)([0-9]{8})$/',
43        'FRA'    => '/^(FR)[0-9]{2}[0-9]{9}$/',
44        'GBR'    => '/^(GB)([0-9]{9}|[0-9]{12}|(GD)[0-4][0-9]{2}|(HA)5[0-9]{2})$/',
45        'GRC'    => '/^(EL)([0-9]{7,9})$/',
46        'HRV'    => '/^(HR)([0-9]{11})$/',
47        'HUN'    => '/^(HU)([0-9]{8})$/',
48        'IRL'    => '/^(IE)([0-9]{7}[A-Z]{1,2}|[0-9][A-Z][0-9]{5}[A-Z])$/',
49        'ITA'    => '/^(IT)([0-9]{11})$/',
50        'LTU'    => '/^(LT)([0-9]{9}|[0-9]{12})$/',
51        'LUX'    => '/^(LU)([0-9]{8})$/',
52        'LVA'    => '/^(LV)([0-9]{11})$/',
53        'MLT'    => '/^(MT)([0-9]{8})$/',
54        'NLD'    => '/^(NL)([0-9]{9}B[0-9]{2})$/',
55        'POL'    => '/^(PL)([0-9]{10}|[0-9]{3}-[0-9]{2}-[0-9]{2}-[0-9]{3})$/',
56        'PRT'    => '/^(PT)([0-9]{9})$/',
57        'ROU'    => '/^(RO)([0-9]{2,10})$/',
58        'SWE'    => '/^(SE)([0-9]{10}[0-9]{2})$/i',
59        'SVN'    => '/^(SI)([0-9]{8})$/',
60        'SVK'    => '/^(SK)([0-9][10])$/',
61    ];
62
63    /**
64     * {@inheritdoc}
65     */
66    public static function isValid(mixed $value, array $constraints = null) : bool
67    {
68        if (!\is_string($value)) {
69            return false;
70        }
71
72        $value = \str_replace(' ', '', \strtoupper($value));
73
74        foreach (self::PATTERNS as $pattern) {
75            if ((bool) \preg_match($pattern, $value)) {
76                // VAT potentially valid
77                return true;
78            } elseif (\stripos($pattern, \substr($value, 0, 2)) !== false) {
79                // Regex found but didn't match, therefore VAT is considered potentially invalid
80                return false;
81            }
82        }
83
84        // Couldn't find possible regex, therefore the VAT is considered potentially valid
85        return true;
86    }
87}