Completed
Push — master ( 5d18c7...cabcf3 )
by Hannes
10s
created

Modulo11::calculateCheckDigit()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 1
dl 0
loc 17
rs 9.4285
c 0
b 0
f 0
ccs 8
cts 8
cp 1
crap 3
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace byrokrat\banking\Validator;
6
7
use byrokrat\banking\Exception\LogicException;
8
9
/**
10
 * Modulo11 calculator
11
 */
12
class Modulo11
13
{
14
    /**
15
     * Map modulo 11 remainder to check digit map
16
     */
17
    private const REMAINDER_TO_CHECK_DIGIT_MAP = [
18
        0 => '0',
19
        1 => '1',
20
        2 => '2',
21
        3 => '3',
22
        4 => '4',
23
        5 => '5',
24
        6 => '6',
25
        7 => '7',
26
        8 => '8',
27
        9 => '9',
28
        10 => 'X',
29
        11 => '0',
30
    ];
31
32
    /**
33
     * Calculate the modulo 11 check digit for number
34
     *
35
     * @throws LogicException If $number is not numerical
36
     */
37 134
    public static function calculateCheckDigit(string $number): string
38
    {
39 134
        if (!ctype_digit($number)) {
40 5
            throw new LogicException(
41 5
                "Number can only contain numerical characters, found '$number'"
42
            );
43
        }
44
45 129
        $sum = 0;
46
47 129
        foreach (array_reverse(str_split($number)) as $pos => $digit) {
48 129
            $sum += $digit * self::getWeight($pos, 2);
49
        }
50
51
        // Calculate check digit from remainder
52 129
        return self::REMAINDER_TO_CHECK_DIGIT_MAP[11 - $sum % 11];
53
    }
54
55
    /**
56
     * Calculate weight based on position in number
57
     *
58
     * @param  int $pos   Position in number (starts from 0)
59
     * @param  int $start Start value for weight calculation (value of position 0)
60
     */
61 129
    protected static function getWeight(int $pos, int $start = 1): int
62
    {
63 129
        $pos += $start;
64
65 129
        while ($pos > 10) {
66 84
            $pos -= 10;
67
        }
68
69 129
        return $pos;
70
    }
71
}
72