Completed
Push — master ( 5d18c7...cabcf3 )
by Hannes
16s queued 13s
created

StrictFactory::createAccount()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 33
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 20
nc 6
nop 1
dl 0
loc 33
rs 8.439
c 0
b 0
f 0
ccs 19
cts 19
cp 1
crap 5
1
<?php
2
3
declare(strict_types = 1);
4
5
namespace byrokrat\banking;
6
7
use byrokrat\banking\Exception\InvalidAccountNumberException;
8
9
/**
10
 * Internal factory creating undefined account numbers (not belongning to a bank)
11
 *
12
 * It is strict in the sense that if fails on any unexpected characters.
13
 *
14
 * For an alternative {@see PermissiveFactory}.
15
 * For a factory that validates account numbers {@see AccountFactory}.
16
 */
17
class StrictFactory implements AccountFactoryInterface
18
{
19
    private const CLEARING_SERIAL_DELIMITER = ',';
20
    private const CLEARING = 'CLEARING';
21
    private const CLEARING_CHECK = 'CLEARING_CHECK';
22
    private const SERIAL = 'SERIAL';
23
    private const CHECK = 'CHECK';
24
25 6
    public function createAccount(string $number): AccountNumber
26
    {
27
        $parts = [
28 6
            self::CLEARING => '',
29 6
            self::CLEARING_CHECK => '',
30 6
            self::SERIAL => '',
31 6
            self::CHECK => '',
32
        ];
33
34 6
        foreach (str_split($number) as $pos => $char) {
35 6
            if ($char == self::CLEARING_SERIAL_DELIMITER) {
36 4
                if (self::terminateClearing($parts)) {
37 2
                    continue;
38
                }
39
            }
40
41 6
            if (!ctype_digit($char)) {
42 3
                throw new InvalidAccountNumberException(
43 3
                    "Invalid char ($char) at position $pos, expecting a digit"
44
                );
45
            }
46
47 6
            self::pushDigit($char, $parts);
48
        }
49
50 3
        return new UndefinedAccount(
51 3
            $number,
52 3
            $parts[self::CLEARING],
53 3
            $parts[self::CLEARING_CHECK],
54 3
            $parts[self::SERIAL],
55 3
            $parts[self::CHECK]
56
        );
57
    }
58
59 6
    private static function pushDigit(string $digit, array &$parts): void
60
    {
61 6
        $pending = $parts[self::CHECK];
62 6
        $parts[self::CHECK] = $digit;
63
64 6
        if (strlen($parts[self::CLEARING]) < 4) {
65 6
            $parts[self::CLEARING] .= $pending;
66
        } else {
67 4
            $parts[self::SERIAL] .= $pending;
68
        }
69 6
    }
70
71 4
    private static function terminateClearing(array &$parts): bool
72
    {
73 4
        $pending = $parts[self::CHECK];
74 4
        $parts[self::CHECK] = '';
75
76 4
        if (strlen($parts[self::CLEARING]) == 3) {
77 1
            $parts[self::CLEARING] .= $pending;
78 1
            return true;
79
        }
80
81 3
        if (strlen($parts[self::CLEARING]) == 4 && !$parts[self::SERIAL]) {
82 1
            $parts[self::CLEARING_CHECK] = $pending;
83 1
            return true;
84
        }
85
86 2
        return false;
87
    }
88
}
89