Passed
Push — master ( 6bed8c...33ba8b )
by Manuel
01:36
created

QrBill::getUltimateCreditor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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