Passed
Pull Request — master (#37)
by Manuel
02:07
created

loadValidatorMetadata()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 14
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 25
rs 9.7998
1
<?php
2
3
namespace Sprain\SwissQrBill\Reference;
4
5
use Sprain\SwissQrBill\Validator\Exception\InvalidQrPaymentReferenceException;
6
use Sprain\SwissQrBill\Validator\SelfValidatableInterface;
7
use Sprain\SwissQrBill\Validator\SelfValidatableTrait;
8
use Symfony\Component\Validator\Constraints as Assert;
9
use Symfony\Component\Validator\Context\ExecutionContextInterface;
10
use Symfony\Component\Validator\Mapping\ClassMetadata;
11
12
class QrPaymentReferenceGenerator implements SelfValidatableInterface
13
{
14
    use SelfValidatableTrait;
15
16
    /** @var string */
17
    private $customerIdentificationNumber;
18
19
    /** @var string */
20
    private $referenceNumber;
21
22
    public static function generate(string $customerIdentificationNumber, string $referenceNumber)
23
    {
24
        $qrPaymentReferenceGenerator = new self();
25
        $qrPaymentReferenceGenerator->customerIdentificationNumber = $qrPaymentReferenceGenerator->removeWhitespace($customerIdentificationNumber);
26
        $qrPaymentReferenceGenerator->referenceNumber = $qrPaymentReferenceGenerator->removeWhitespace($referenceNumber);
27
28
        return $qrPaymentReferenceGenerator->doGenerate();
29
    }
30
31
    public function getCustomerIdentificationNumber(): ?string
32
    {
33
        return $this->customerIdentificationNumber;
34
    }
35
36
    public function getReferenceNumber(): ?string
37
    {
38
        return $this->referenceNumber;
39
    }
40
41
    private function doGenerate()
42
    {
43
        if (!$this->isValid()) {
44
            throw new InvalidQrPaymentReferenceException(
45
                'The provided data is not valid to generate a qr payment reference number. Use getViolations() to find details.'
46
            );
47
        }
48
49
        $completeReferenceNumber  = $this->getCustomerIdentificationNumber();
50
        $completeReferenceNumber .= str_pad($this->getReferenceNumber(), 26 - strlen($completeReferenceNumber), '0', STR_PAD_LEFT);
51
        $completeReferenceNumber .= $this->modulo10($completeReferenceNumber);
52
53
        return $completeReferenceNumber;
54
    }
55
56
    public static function loadValidatorMetadata(ClassMetadata $metadata): void
57
    {
58
        $metadata->addPropertyConstraints('customerIdentificationNumber', [
59
            // Only numbers are allowed (including leading zeros)
60
            new Assert\Regex([
61
                'pattern' => '/^\d*$/',
62
                'match' => true
63
            ]),
64
            new Assert\Length([
65
                'max' => 11,
66
                'min' => 4
67
            ]),
68
            new Assert\NotBlank()
69
        ]);
70
71
        $metadata->addPropertyConstraints('referenceNumber', [
72
            // Only numbers are allowed (including leading zeros)
73
            new Assert\Regex([
74
                'pattern' => '/^\d*$/',
75
                'match' => true
76
            ]),
77
            new Assert\NotBlank()
78
        ]);
79
80
        $metadata->addConstraint(new Assert\Callback('validateFullReference'));
81
    }
82
83
    public function validateFullReference(ExecutionContextInterface $context, $payload)
0 ignored issues
show
Unused Code introduced by
The parameter $payload is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

83
    public function validateFullReference(ExecutionContextInterface $context, /** @scrutinizer ignore-unused */ $payload)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
84
    {
85
        if (strlen($this->customerIdentificationNumber) + strlen($this->referenceNumber) > 26) {
86
            $context->buildViolation('The length of customer identification number + reference number may not exceed 26 characters in total.')
87
                ->addViolation();
88
        }
89
    }
90
91
    private function removeWhitespace(string $string): string
92
    {
93
        return preg_replace('/\s+/', '', $string);
94
    }
95
96
    private function modulo10($number)
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 + substr($number, $i, 1)) % 10];
102
        }
103
104
        return (10 - $next) % 10;
105
    }
106
}
107