Passed
Pull Request — master (#71)
by
unknown
03:43
created

QrPaymentReferenceGenerator::removeWhitespace()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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