Passed
Push — master ( 857a9a...cc2b96 )
by Manuel
01:58
created

QrBill::getQrCode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 0
dl 0
loc 16
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Sprain\SwissQrBill;
4
5
use Endroid\QrCode\QrCode;
6
use Sprain\SwissQrBill\DataGroups\Address;
7
use Sprain\SwissQrBill\DataGroups\AlternativeScheme;
8
use Sprain\SwissQrBill\DataGroups\CreditorInformation;
9
use Sprain\SwissQrBill\DataGroups\Header;
10
use Sprain\SwissQrBill\DataGroups\Interfaces\QrCodeData;
11
use Sprain\SwissQrBill\DataGroups\PaymentAmountInformation;
12
use Sprain\SwissQrBill\DataGroups\PaymentReference;
13
use Sprain\SwissQrBill\Exception\InvalidQrBillDataException;
14
use Sprain\SwissQrBill\String\StringModifier;
15
use Sprain\SwissQrBill\Validator\Interfaces\Validatable;
16
use Sprain\SwissQrBill\Validator\ValidatorTrait;
17
use Symfony\Component\Validator\Constraints as Assert;
18
use Symfony\Component\Validator\Mapping\ClassMetadata;
19
20
class QrBill implements Validatable
21
{
22
    use ValidatorTrait;
23
24
    const SWISS_CROSS_LOGO_FILE = __DIR__ . '/../assets/swiss-cross.png';
25
26
    /** @var Header */
27
    private $header;
28
29
    /** @var CreditorInformation */
30
    private $creditorInformation;
31
32
    /** @var Address */
33
    private $creditor;
34
35
    /** @var Address */
36
    private $ultimateCreditor;
37
38
    /** @var PaymentAmountInformation */
39
    private $paymentAmountInformation;
40
41
    /** @var Address */
42
    private $ultimateDebtor;
43
44
    /** @var PaymentReference */
45
    private $paymentReference;
46
47
    /** @var AlternativeScheme[] */
48
    private $alternativeSchemes = [];
49
50
    public static function create() : self
51
    {
52
        $header = new Header();
53
        $header->setCoding(Header::CODING_LATIN);
54
        $header->setQrType(Header::QRTYPE_SPC);
55
        $header->setVersion(Header::VERSION_0100);
56
57
        $qrBill = new self();
58
        $qrBill->setHeader($header);
59
60
        return $qrBill;
61
    }
62
63
    public function getHeader(): Header
64
    {
65
        return $this->header;
66
    }
67
68
    public function setHeader(Header $header) : self
69
    {
70
        $this->header = $header;
71
        
72
        return $this;
73
    }
74
75
    public function getCreditorInformation(): CreditorInformation
76
    {
77
        return $this->creditorInformation;
78
    }
79
80
    public function setCreditorInformation(CreditorInformation $creditorInformation) : self
81
    {
82
        $this->creditorInformation = $creditorInformation;
83
84
        return $this;
85
    }
86
87
    public function getCreditor(): Address
88
    {
89
        return $this->creditor;
90
    }
91
92
    public function setCreditor(Address $creditor) : self
93
    {
94
        $this->creditor = $creditor;
95
        
96
        return $this;
97
    }
98
99
    public function getUltimateCreditor(): ?Address
100
    {
101
        return $this->ultimateCreditor;
102
    }
103
104
    public function setUltimateCreditor(Address $ultimateCreditor) : self
105
    {
106
        $this->ultimateCreditor = $ultimateCreditor;
107
        
108
        return $this;
109
    }
110
111
    public function getPaymentAmountInformation(): PaymentAmountInformation
112
    {
113
        return $this->paymentAmountInformation;
114
    }
115
116
    public function setPaymentAmountInformation(PaymentAmountInformation $paymentAmountInformation) : self
117
    {
118
        $this->paymentAmountInformation = $paymentAmountInformation;
119
        
120
        return $this;
121
    }
122
123
    public function getUltimateDebtor(): ?Address
124
    {
125
        return $this->ultimateDebtor;
126
    }
127
128
    public function setUltimateDebtor(Address $ultimateDebtor) : self
129
    {
130
        $this->ultimateDebtor = $ultimateDebtor;
131
        
132
        return $this;
133
    }
134
135
    public function getPaymentReference(): PaymentReference
136
    {
137
        return $this->paymentReference;
138
    }
139
140
    public function setPaymentReference(PaymentReference $paymentReference) : self
141
    {
142
        $this->paymentReference = $paymentReference;
143
        
144
        return $this;
145
    }
146
147
    public function getAlternativeSchemes(): array
148
    {
149
        return $this->alternativeSchemes;
150
    }
151
152
    public function setAlternativeSchemes(array $alternativeSchemes) : self
153
    {
154
        $this->alternativeSchemes = $alternativeSchemes;
155
156
        return $this;
157
    }
158
159
    public function addAlternativeScheme(AlternativeScheme $alternativeScheme) : self
160
    {
161
        $this->alternativeSchemes[] = $alternativeScheme;
162
163
        return $this;
164
    }
165
166
    public function getQrCode() : QrCode
167
    {
168
        if (!$this->isValid()) {
169
            throw new InvalidQrBillDataException(
170
                'The provided data is not valid to generate a qr code. Use getViolations() to find details.'
171
            );
172
        }
173
174
        $qrCode = new QrCode();
175
        $qrCode->setText($this->getQrCodeData());
176
        $qrCode->setSize(543); // recommended 46x46 mm in px @ 300dpi
177
        $qrCode->setMargin(19); // recommended 1,6 mm in px @ 300dpi
178
        $qrCode->setLogoPath(self::SWISS_CROSS_LOGO_FILE);
179
        $qrCode->setLogoWidth(83); // recommended 7x7 mm in px @ 300dpi
180
181
        return $qrCode;
182
    }
183
184
    private function getQrCodeData() : string
185
    {
186
        $elements = [
187
            $this->getHeader(),
188
            $this->getCreditorInformation(),
189
            $this->getCreditor(),
190
            $this->getUltimateCreditor() ?: new Address(),
191
            $this->getPaymentAmountInformation(),
192
            $this->getUltimateDebtor() ?: new Address(),
193
            $this->getPaymentReference(),
194
            $this->getAlternativeSchemes()
195
        ];
196
197
        $qrCodeStringElements = $this->extractQrCodeDataFromElements($elements);
198
199
        return implode("\r\n", $qrCodeStringElements);
200
    }
201
202
    private function extractQrCodeDataFromElements(array $elements) : array
203
    {
204
        $qrCodeElements = [];
205
206
        foreach ($elements as $element) {
207
            if ($element instanceof QrCodeData) {
208
                $qrCodeElements = array_merge($qrCodeElements, $element->getQrCodeData());
209
            } elseif (is_array($element)) {
210
                $qrCodeElements = array_merge($qrCodeElements, $this->extractQrCodeDataFromElements($element));
211
            }
212
        }
213
214
        array_walk($qrCodeElements, function(&$string){
215
            $string = StringModifier::replaceLineBreaksWithString($string);
216
            $string = StringModifier::replaceMultipleSpacesWithOne($string);
217
            $string = trim($string);
218
        });
219
220
        return $qrCodeElements;
221
    }
222
223
    public static function loadValidatorMetadata(ClassMetadata $metadata)
224
    {
225
        $metadata->addPropertyConstraints('header', [
226
            new Assert\NotNull(),
227
            new Assert\Valid()
228
        ]);
229
230
        $metadata->addPropertyConstraints('creditorInformation', [
231
            new Assert\NotNull(),
232
            new Assert\Valid()
233
        ]);
234
235
        $metadata->addPropertyConstraints('creditor', [
236
            new Assert\NotNull(),
237
            new Assert\Valid()
238
        ]);
239
240
        $metadata->addPropertyConstraints('ultimateCreditor', [
241
            new Assert\Valid()
242
        ]);
243
244
        $metadata->addPropertyConstraints('paymentAmountInformation', [
245
            new Assert\NotNull(),
246
            new Assert\Valid()
247
        ]);
248
249
        $metadata->addPropertyConstraints('ultimateDebtor', [
250
            new Assert\Valid()
251
        ]);
252
253
        $metadata->addPropertyConstraints('paymentReference', [
254
            new Assert\NotNull(),
255
            new Assert\Valid()
256
        ]);
257
258
        $metadata->addPropertyConstraints('alternativeSchemes', [
259
            new Assert\Count([
260
                'max' => 2
261
            ]),
262
            new Assert\Valid()
263
        ]);
264
    }
265
}
266