Validator   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
eloc 49
c 3
b 0
f 0
dl 0
loc 141
rs 10
wmc 18

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A isValid() 0 23 5
A luhn() 0 15 5
A validDate() 0 4 2
A validate() 0 18 4
A formatNumber() 0 6 1
1
<?php
2
3
namespace Olssonm\IdentityNumber;
4
5
use DateTime;
6
7
/**
8
 * Main validation class
9
 */
10
class Validator
11
{
12
    const IDENTITYNUMBER = 'personal_identity_number';
13
14
    const ORGANIZATIONNUMBER = 'organization_number';
15
16
    const COORDINATIONNUMBER = 'coordination_number';
17
18
    /**
19
     * Current validation type
20
     *
21
     * @var string
22
     */
23
    protected $type;
24
25
    /**
26
     * Numbers that actually passes the Luhn-algorithm but
27
     * that are non-valid
28
     *
29
     * @var array
30
     */
31
    protected $invalidNumbers = [
32
        '0000000000',
33
        '2222222222',
34
        '4444444444',
35
        '5555555555',
36
        '7777777777',
37
        '9999999999'
38
    ];
39
40
    public function __construct()
41
    {
42
        //
43
    }
44
45
    /**
46
     * Main validation method
47
     *
48
     * @param  string  $number the number under validation
49
     * @return boolean
50
     */
51
    public function isValid($number)
52
    {
53
        $number = $this->formatNumber($number);
54
55
        if (!$number) {
56
            return false;
57
        }
58
59
        switch ($this->type) {
60
            case Validator::IDENTITYNUMBER:
61
                return $this->validate($number, true);
62
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
63
64
            case Validator::ORGANIZATIONNUMBER:
65
                return $this->validate($number, false);
66
                break;
67
68
            case Validator::COORDINATIONNUMBER:
69
                return $this->validate($number, false);
70
                break;
71
        }
72
73
        return false;
74
    }
75
76
    /**
77
     * Internal validator
78
     *
79
     * @param  string   $number     the value under validation
80
     * @param  boolean  $checkDate if date validation is to be performed
81
     * @return boolean
82
     */
83
    private function validate($number, $checkDate)
84
    {
85
        // Perform simple test on invalid numbers
86
        if (in_array($number, $this->invalidNumbers)) {
87
            return false;
88
        }
89
90
        // If checking for a date
91
        if ($checkDate == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
92
            $dateTest = substr($number, 0, 6);
93
            $validDate = $this->validDate($dateTest);
94
            if ($validDate == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
95
                return false;
96
            }
97
        }
98
99
        // Check luhn
100
        return $this->luhn($number);
101
    }
102
103
    /**
104
     * Run the IdentityNumberFormatter on the specified number
105
     *
106
     * @param  string $number
107
     * @return string
108
     */
109
    protected function formatNumber($number)
110
    {
111
        $formatter = new IdentityNumberFormatter($number, 10, false);
112
        $value = $formatter->getFormatted();
113
114
        return $value;
115
    }
116
117
    /**
118
     * Perform luhn validation
119
     *
120
     * @param  string $number
121
     * @return boolean
122
     */
123
    private function luhn($number)
124
    {
125
        settype($number, 'string');
126
        $number = array_reverse(str_split($number));
127
        $sum = 0;
128
        foreach ($number as $key => $number) {
0 ignored issues
show
introduced by
$number is overwriting one of the parameters of this function.
Loading history...
129
            if (!is_numeric($number)) {
130
                return false;
131
            }
132
            if ($key % 2) {
133
                $number = $number * 2;
134
            }
135
            $sum += ($number >= 10 ? $number - 9 : $number);
136
        }
137
        return ($sum % 10 === 0);
138
    }
139
140
    /**
141
     * Validate a date as a format
142
     *
143
     * @param  string $dateTest     the date to be tested
144
     * @param  string $format       the date format
145
     * @return boolean
146
     */
147
    private function validDate($dateTest, $format = 'ymd')
148
    {
149
        $date = DateTime::createFromFormat('ymd', $dateTest);
150
        return $date && $date->format($format) == $dateTest;
151
    }
152
}
153