Completed
Push — master ( 3bd2d9...08bef3 )
by Manuel
03:54
created

QrBill::setAdditionalInformation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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