Passed
Pull Request — master (#137)
by
unknown
12:27
created

FpdfOutput::addSwissQrCodeImage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 11
rs 10
cc 1
nc 1
nop 0
1
<?php declare(strict_types=1);
2
3
4
namespace Sprain\SwissQrBill\PaymentPart\Output\FpdfOutput;
5
6
use Fpdf\Fpdf;
7
use Sprain\SwissQrBill\Exception\InvalidFpdfImageFormat;
8
use Sprain\SwissQrBill\PaymentPart\Output\AbstractOutput;
9
use Sprain\SwissQrBill\PaymentPart\Output\Element\OutputElementInterface;
10
use Sprain\SwissQrBill\PaymentPart\Output\Element\Placeholder;
11
use Sprain\SwissQrBill\PaymentPart\Output\Element\Text;
12
use Sprain\SwissQrBill\PaymentPart\Output\Element\Title;
13
use Sprain\SwissQrBill\PaymentPart\Output\OutputInterface;
14
use Sprain\SwissQrBill\PaymentPart\Translation\Translation;
15
use Sprain\SwissQrBill\QrBill;
16
use Sprain\SwissQrBill\QrCode\QrCode;
17
18
final class FpdfOutput extends AbstractOutput implements OutputInterface
19
{
20
    // FPDF
21
    private const BORDER = 0;
22
    private const ALIGN_LEFT = 'L';
23
    private const ALIGN_RIGHT = 'R';
24
    private const ALIGN_CENTER = 'C';
25
    private const FONT = 'Helvetica';
26
27
    // Location
28
    private const CURRENCY_AMOUNT_Y = 259.3;
29
    private const AMOUNT_LINE_SPACING = 1.2;
30
    private const AMOUNT_LINE_SPACING_RCPT = 0.6;
31
    private const LEFT_PART_X = 4;
32
    private const RIGHT_PART_X = 66;
33
    private const RIGHT_PART_X_INFO = 117;
34
    private const TITLE_Y = 195.2;
35
36
    // Font size
37
    private const FONT_SIZE_MAIN_TITLE = 11;
38
    private const FONT_SIZE_TITLE_RECEIPT = 6;
39
    private const FONT_SIZE_RECEIPT = 8;
40
    private const FONT_SIZE_TITLE_PAYMENT_PART = 8;
41
    private const FONT_SIZE_PAYMENT_PART = 10;
42
    private const FONT_SIZE_FURTHER_INFORMATION = 7;
43
44
    // Line spacing
45
    private const LINE_SPACING_RECEIPT = 3.4;
46
    private const LINE_SPACING_PAYMENT_PART = 4.8;
47
    private float $amountLS = 0;
48
49
    private Fpdf $fpdf;
50
    private float $offsetX;
51
    private float $offsetY;
52
53
    public function __construct(
54
        QrBill $qrBill,
55
        string $language,
56
        Fpdf   $fpdf,
57
        float  $offsetX = 0,
58
        float  $offsetY = 0
59
    ) {
60
        parent::__construct($qrBill, $language);
61
        $this->fpdf = $fpdf;
62
        $this->offsetX = $offsetX;
63
        $this->offsetY = $offsetY;
64
        $this->setQrCodeImageFormat(QrCode::FILE_FORMAT_PNG);
65
    }
66
67
    public function getPaymentPart()
68
    {
69
        $this->fpdf->SetAutoPageBreak(false);
70
71
        $this->addSeparatorContentIfNotPrintable();
72
73
        $this->addInformationContentReceipt();
74
        $this->addCurrencyContentReceipt();
75
        $this->addAmountContentReceipt();
76
77
        $this->addSwissQrCodeImage();
78
        $this->addInformationContent();
79
        $this->addCurrencyContent();
80
        $this->addAmountContent();
81
        $this->addFurtherInformationContent();
82
    }
83
84
    public function setQrCodeImageFormat(string $fileExtension): AbstractOutput
85
    {
86
        if ($fileExtension === 'svg') {
87
            throw new InvalidFpdfImageFormat('SVG images are not allowed by FPDF.');
88
        }
89
90
        $this->qrCodeImageFormat = $fileExtension;
91
92
        return $this;
93
    }
94
95
    private function addSwissQrCodeImage(): void
96
    {
97
        $qrCode = $this->getQrCode();
98
        $qrCode->setWriterByExtension(
99
            $this->getQrCodeImageFormat()
100
        );
101
102
        $yPosQrCode = 209.5 + $this->offsetY;
103
        $xPosQrCode = 67 + $this->offsetX;
104
105
        $this->fpdf->Image($qrCode->writeDataUri(), $xPosQrCode, $yPosQrCode, 46, 46, 'png');
106
    }
107
108
    private function addInformationContentReceipt(): void
109
    {
110
        // Title
111
        $this->fpdf->SetFont(self::FONT, 'B', self::FONT_SIZE_MAIN_TITLE);
112
        $this->SetXY(self::LEFT_PART_X, self::TITLE_Y);
113
        $this->fpdf->MultiCell(0, 7, $this->convertText(Translation::get('receipt', $this->language)));
0 ignored issues
show
Bug introduced by
It seems like Sprain\SwissQrBill\Payme...eipt', $this->language) can also be of type null; however, parameter $text of Sprain\SwissQrBill\Payme...dfOutput::convertText() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

113
        $this->fpdf->MultiCell(0, 7, $this->convertText(/** @scrutinizer ignore-type */ Translation::get('receipt', $this->language)));
Loading history...
114
115
        // Elements
116
        $this->SetY(204);
117
        foreach ($this->getInformationElementsOfReceipt() as $receiptInformationElement) {
118
            $this->SetX(self::LEFT_PART_X);
119
            $this->setContentElement($receiptInformationElement, true);
120
        }
121
122
        // Acceptance section
123
        $this->fpdf->SetFont(self::FONT, 'B', self::FONT_SIZE_TITLE_RECEIPT);
124
        $this->SetXY(self::LEFT_PART_X, 274.3);
125
        $this->fpdf->Cell(54, 0, $this->convertText(Translation::get('acceptancePoint', $this->language)), self::BORDER, '', self::ALIGN_RIGHT);
126
    }
127
128
    private function addInformationContent(): void
129
    {
130
        // Title
131
        $this->fpdf->SetFont(self::FONT, 'B', self::FONT_SIZE_MAIN_TITLE);
132
        $this->SetXY(self::RIGHT_PART_X, 195.2);
133
        $this->fpdf->MultiCell(48, 7, $this->convertText(Translation::get('paymentPart', $this->language)));
0 ignored issues
show
Bug introduced by
It seems like Sprain\SwissQrBill\Payme...Part', $this->language) can also be of type null; however, parameter $text of Sprain\SwissQrBill\Payme...dfOutput::convertText() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

133
        $this->fpdf->MultiCell(48, 7, $this->convertText(/** @scrutinizer ignore-type */ Translation::get('paymentPart', $this->language)));
Loading history...
134
135
        // Elements
136
        $this->SetY(197.3);
137
        foreach ($this->getInformationElements() as $informationElement) {
138
            $this->SetX(self::RIGHT_PART_X_INFO);
139
            $this->setContentElement($informationElement, false);
140
        }
141
    }
142
143
    private function addCurrencyContentReceipt(): void
144
    {
145
        $this->SetY(self::CURRENCY_AMOUNT_Y);
146
        foreach ($this->getCurrencyElements() as $receiptCurrencyElement) {
147
            $this->amountLS = self::AMOUNT_LINE_SPACING_RCPT;
148
            $this->SetX(self::LEFT_PART_X);
149
            $this->setContentElement($receiptCurrencyElement, true);
150
            $this->amountLS = 0;
151
        }
152
    }
153
154
    private function addAmountContentReceipt(): void
155
    {
156
        $this->SetY(self::CURRENCY_AMOUNT_Y);
157
        foreach ($this->getAmountElementsReceipt() as $receiptAmountElement) {
158
            $this->amountLS = self::AMOUNT_LINE_SPACING_RCPT;
159
            $this->SetX(16);
160
            $this->setContentElement($receiptAmountElement, true);
161
            $this->amountLS = 0;
162
        }
163
    }
164
165
    private function addCurrencyContent(): void
166
    {
167
        $this->SetY(self::CURRENCY_AMOUNT_Y);
168
        foreach ($this->getCurrencyElements() as $currencyElement) {
169
            $this->amountLS = self::AMOUNT_LINE_SPACING;
170
            $this->SetX(self::RIGHT_PART_X);
171
            $this->setContentElement($currencyElement, false);
172
            $this->amountLS = 0;
173
        }
174
    }
175
176
    private function addAmountContent(): void
177
    {
178
        $this->SetY(self::CURRENCY_AMOUNT_Y);
179
        foreach ($this->getAmountElements() as $amountElement) {
180
            $this->amountLS = self::AMOUNT_LINE_SPACING;
181
            $this->SetX(80);
182
            $this->setContentElement($amountElement, false);
183
            $this->amountLS = 0;
184
        }
185
    }
186
187
    private function addFurtherInformationContent(): void
188
    {
189
        $this->SetXY(self::RIGHT_PART_X, 286);
190
        $this->fpdf->SetFont(self::FONT, '', self::FONT_SIZE_FURTHER_INFORMATION);
191
192
        foreach ($this->getFurtherInformationElements() as $furtherInformationElement) {
193
            $this->SetX(self::RIGHT_PART_X);
194
            $this->setContentElement($furtherInformationElement, true);
195
        }
196
    }
197
198
    private function addSeparatorContentIfNotPrintable()
199
    {
200
        if (!$this->isPrintable()) {
201
            $this->fpdf->SetLineWidth(0.1);
202
            $this->fpdf->Line(2 + $this->offsetX, 193 + $this->offsetY, 208 + $this->offsetX, 193 + $this->offsetY);
203
            $this->fpdf->Line(62 + $this->offsetX, 193 + $this->offsetY, 62 + $this->offsetX, 296 + $this->offsetY);
204
            $this->fpdf->SetFont(self::FONT, '', self::FONT_SIZE_FURTHER_INFORMATION);
205
            $this->SetY(189.6);
206
            $this->fpdf->MultiCell(0, 0, $this->convertText(Translation::get('separate', $this->language)), self::BORDER, self::ALIGN_CENTER);
0 ignored issues
show
Bug introduced by
It seems like Sprain\SwissQrBill\Payme...rate', $this->language) can also be of type null; however, parameter $text of Sprain\SwissQrBill\Payme...dfOutput::convertText() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

206
            $this->fpdf->MultiCell(0, 0, $this->convertText(/** @scrutinizer ignore-type */ Translation::get('separate', $this->language)), self::BORDER, self::ALIGN_CENTER);
Loading history...
207
        }
208
    }
209
210
    private function setContentElement(OutputElementInterface $element, bool $isReceiptPart): void
211
    {
212
        if ($element instanceof Title) {
213
            $this->setTitleElement($element, $isReceiptPart);
214
        }
215
216
        if ($element instanceof Text) {
217
            $this->setTextElement($element, $isReceiptPart);
218
        }
219
220
        if ($element instanceof Placeholder) {
221
            $this->setPlaceholderElement($element);
222
        }
223
    }
224
225
    private function setTitleElement(Title $element, bool $isReceiptPart): void
226
    {
227
        $this->fpdf->SetFont(self::FONT, 'B', $isReceiptPart ? self::FONT_SIZE_TITLE_RECEIPT : self::FONT_SIZE_TITLE_PAYMENT_PART);
228
        $this->fpdf->MultiCell(0, 2.8, $this->convertText(
229
            Translation::get(str_replace("text.", "", $element->getTitle()), $this->language)
0 ignored issues
show
Bug introduced by
It seems like Sprain\SwissQrBill\Payme...le()), $this->language) can also be of type null; however, parameter $text of Sprain\SwissQrBill\Payme...dfOutput::convertText() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

229
            /** @scrutinizer ignore-type */ Translation::get(str_replace("text.", "", $element->getTitle()), $this->language)
Loading history...
230
        ));
231
        $this->fpdf->Ln($this->amountLS);
232
    }
233
234
    private function setTextElement(Text $element, bool $isReceiptPart): void
235
    {
236
        $this->fpdf->SetFont(self::FONT, '', $isReceiptPart ? self::FONT_SIZE_RECEIPT : self::FONT_SIZE_PAYMENT_PART);
237
        $this->fpdf->MultiCell(
238
            $isReceiptPart ? 54 : 0,
239
            $isReceiptPart ? 3.3 : 4,
240
            str_replace("text.", "", $this->convertText($element->getText())),
241
            self::BORDER,
242
            self::ALIGN_LEFT
243
        );
244
        $this->fpdf->Ln($isReceiptPart ? self::LINE_SPACING_RECEIPT : self::LINE_SPACING_PAYMENT_PART);
245
    }
246
247
    private function setPlaceholderElement(Placeholder $element): void
248
    {
249
        $type = $element->getType();
250
251
        switch ($type) {
252
            case Placeholder::PLACEHOLDER_TYPE_AMOUNT['type']:
253
                $y = $this->fpdf->GetY() + 1;
254
                $x = $this->fpdf->GetX() - 2;
255
                break;
256
            case Placeholder::PLACEHOLDER_TYPE_AMOUNT_RECEIPT['type']:
257
                $y = $this->fpdf->GetY() - 2;
258
                $x = $this->fpdf->GetX() + 11;
259
                break;
260
            case Placeholder::PLACEHOLDER_TYPE_PAYABLE_BY['type']:
261
            case Placeholder::PLACEHOLDER_TYPE_PAYABLE_BY_RECEIPT['type']:
262
            default:
263
                $y = $this->fpdf->GetY() + 1;
264
                $x = $this->fpdf->GetX() + 1;
265
        }
266
267
        $this->fpdf->Image(
268
            $element->getFile(Placeholder::FILE_TYPE_PNG),
269
            $x,
270
            $y,
271
            $element->getWidth(),
272
            $element->getHeight()
273
        );
274
    }
275
276
    private function setX(float $x): void
277
    {
278
        $this->fpdf->SetX($x + $this->offsetX);
279
    }
280
281
    private function setY(float $y): void
282
    {
283
        $this->fpdf->SetY($y + $this->offsetY);
284
    }
285
286
    private function SetXY(float $x, float $y): void
287
    {
288
        $this->fpdf->SetXY($x + $this->offsetX, $y + $this->offsetY);
289
    }
290
291
    private function convertText(string $text)
292
    {
293
        $text = stripslashes($text);
294
        return iconv('UTF-8', 'CP1250//TRANSLIT', $text);
295
    }
296
}
297