Passed
Push — master ( 903b32...e503ad )
by Manuel
06:03
created

QrPaymentReferenceGenerator::modulo10()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 5
c 2
b 0
f 0
dl 0
loc 9
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Sprain\SwissQrBill\Reference;
4
5
use Sprain\SwissQrBill\String\StringModifier;
6
use Sprain\SwissQrBill\Validator\Exception\InvalidQrPaymentReferenceException;
7
use Sprain\SwissQrBill\Validator\SelfValidatableInterface;
8
use Sprain\SwissQrBill\Validator\SelfValidatableTrait;
9
use Symfony\Component\Validator\Constraints as Assert;
10
use Symfony\Component\Validator\Context\ExecutionContextInterface;
11
use Symfony\Component\Validator\Mapping\ClassMetadata;
12
13
class QrPaymentReferenceGenerator implements SelfValidatableInterface
14
{
15
    use SelfValidatableTrait;
16
17
    /** @var string */
18
    private $customerIdentificationNumber;
19
20
    /** @var string */
21
    private $referenceNumber;
22
23
    public static function generate(?string $customerIdentificationNumber, string $referenceNumber): string
24
    {
25
        $qrPaymentReferenceGenerator = new self($customerIdentificationNumber, $referenceNumber);
26
27
        return $qrPaymentReferenceGenerator->doGenerate();
28
    }
29
30
    public function __construct(?string $customerIdentificationNumber, string $referenceNumber)
31
    {
32
        if (null !== $customerIdentificationNumber) {
33
            $this->customerIdentificationNumber = StringModifier::stripWhitespace($customerIdentificationNumber);
34
        }
35
        $this->referenceNumber = StringModifier::stripWhitespace($referenceNumber);
36
    }
37
38
    public function getCustomerIdentificationNumber(): ?string
39
    {
40
        return $this->customerIdentificationNumber;
41
    }
42
43
    public function getReferenceNumber(): ?string
44
    {
45
        return $this->referenceNumber;
46
    }
47
48
    public function doGenerate(): string
49
    {
50
        if (!$this->isValid()) {
51
            throw new InvalidQrPaymentReferenceException(
52
                'The provided data is not valid to generate a qr payment reference number.'
53
            );
54
        }
55
56
        $completeReferenceNumber  = $this->getCustomerIdentificationNumber();
57
        $completeReferenceNumber .= str_pad($this->getReferenceNumber(), 26 - strlen($completeReferenceNumber), '0', STR_PAD_LEFT);
58
        $completeReferenceNumber .= $this->modulo10($completeReferenceNumber);
59
60
        return $completeReferenceNumber;
61
    }
62
63
    public static function loadValidatorMetadata(ClassMetadata $metadata): void
64
    {
65
        $metadata->addPropertyConstraints('customerIdentificationNumber', [
66
            // Only numbers are allowed (including leading zeros)
67
            new Assert\Regex([
68
                'pattern' => '/^\d*$/',
69
                'match' => true
70
            ]),
71
            new Assert\Length([
72
                'max' => 11
73
            ]),
74
        ]);
75
76
        $metadata->addPropertyConstraints('referenceNumber', [
77
            // Only numbers are allowed (including leading zeros)
78
            new Assert\Regex([
79
                'pattern' => '/^\d*$/',
80
                'match' => true
81
            ]),
82
            new Assert\NotBlank()
83
        ]);
84
85
        $metadata->addConstraint(new Assert\Callback('validateFullReference'));
86
    }
87
88
    public function validateFullReference(ExecutionContextInterface $context): void
89
    {
90
        if (strlen($this->customerIdentificationNumber) + strlen($this->referenceNumber) > 26) {
91
            $context->buildViolation('The length of customer identification number + reference number may not exceed 26 characters in total.')
92
                ->addViolation();
93
        }
94
    }
95
96
    private function modulo10(string $number): int
97
    {
98
        $table = array(0, 9, 4, 6, 8, 2, 7, 1, 3, 5);
99
        $next = 0;
100
        for ($i = 0; $i < strlen($number); $i++) {
101
            $next =  $table[($next + intval(substr($number, $i, 1))) % 10];
102
        }
103
104
        return (10 - $next) % 10;
105
    }
106
}
107