Passed
Pull Request — master (#136)
by
unknown
03:38
created

TcPdfOutput::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 6
c 4
b 0
f 0
dl 0
loc 14
rs 10
cc 1
nc 1
nop 6
1
<?php declare(strict_types=1);
2
3
namespace Sprain\SwissQrBill\PaymentPart\Output\TcPdfOutput;
4
5
use Sprain\SwissQrBill\PaymentPart\Output\AbstractOutput;
6
use Sprain\SwissQrBill\PaymentPart\Output\Element\OutputElementInterface;
7
use Sprain\SwissQrBill\PaymentPart\Output\Element\Placeholder;
8
use Sprain\SwissQrBill\PaymentPart\Output\Element\Text;
9
use Sprain\SwissQrBill\PaymentPart\Output\Element\Title;
10
use Sprain\SwissQrBill\PaymentPart\Output\OutputInterface;
11
use Sprain\SwissQrBill\QrCode\QrCode;
12
use Sprain\SwissQrBill\PaymentPart\Translation\Translation;
13
use Sprain\SwissQrBill\QrBill;
14
use TCPDF;
15
16
final class TcPdfOutput extends AbstractOutput implements OutputInterface
17
{
18
    // TCPDF
19
    private const BORDER = 0;
20
    private const ALIGN_BELOW = 2;
21
    private const ALIGN_LEFT = 'L';
22
    private const ALIGN_RIGHT = 'R';
23
    private const ALIGN_CENTER = 'C';
24
25
    // Ratio
26
    private const LEFT_CELL_HEIGHT_RATIO_COMMON = 1.2;
27
    private const RIGHT_CELL_HEIGHT_RATIO_COMMON = 1.1;
28
    private const LEFT_CELL_HEIGHT_RATIO_CURRENCY_AMOUNT = 1.5;
29
    private const RIGHT_CELL_HEIGHT_RATIO_CURRENCY_AMOUNT = 1.5;
30
31
    // Location
32
    private const CURRENCY_AMOUNT_Y = 259;
33
    private const LEFT_PART_X = 4;
34
    private const RIGHT_PART_X = 66;
35
    private const RIGHT_PART_X_INFO = 117;
36
    private const TITLE_Y = 195;
37
38
    // Font
39
    private const FONT_SIZE_MAIN_TITLE = 11;
40
    private const FONT_SIZE_TITLE_RECEIPT = 6;
41
    private const FONT_SIZE_RECEIPT = 8;
42
    private const FONT_SIZE_TITLE_PAYMENT_PART = 8;
43
    private const FONT_SIZE_PAYMENT_PART = 10;
44
    private const FONT_SIZE_FURTHER_INFORMATION = 7;
45
46
    // Line spacing
47
    private const LINE_SPACING_RECEIPT = 3.5;
48
    private const LINE_SPACING_PAYMENT_PART = 4.8;
49
50
    private TCPDF $tcPdf;
51
    private float $offsetX;
52
    private float $offsetY;
53
    private string $font;
54
55
    public function __construct(
56
        QrBill $qrBill,
57
        string $language,
58
        TCPDF $tcPdf,
59
        float $offsetX = 0,
60
        float $offsetY = 0,
61
        string $font = 'Helvetica'
62
    ) {
63
        parent::__construct($qrBill, $language);
64
        $this->tcPdf = $tcPdf;
65
        $this->offsetX = $offsetX;
66
        $this->offsetY = $offsetY;
67
        $this->font = $font;
68
        $this->setQrCodeImageFormat(QrCode::FILE_FORMAT_SVG);
69
    }
70
71
    public function getPaymentPart(): void
72
    {
73
        $retainCellHeightRatio = $this->tcPdf->getCellHeightRatio();
74
75
        $this->tcPdf->SetAutoPageBreak(false);
76
77
        $this->addSeparatorContentIfNotPrintable();
78
79
        $this->addInformationContentReceipt();
80
        $this->addCurrencyContentReceipt();
81
        $this->addAmountContentReceipt();
82
83
        $this->addSwissQrCodeImage();
84
        $this->addInformationContent();
85
        $this->addCurrencyContent();
86
        $this->addAmountContent();
87
        $this->addFurtherInformationContent();
88
89
        $this->tcPdf->setCellHeightRatio($retainCellHeightRatio);
90
    }
91
92
    private function addSwissQrCodeImage(): void
93
    {
94
        $qrCode = $this->getQrCode();
95
96
        switch ($this->getQrCodeImageFormat()) {
97
            case QrCode::FILE_FORMAT_SVG:
98
                $format = QrCode::FILE_FORMAT_SVG;
99
                $method = "ImageSVG";
100
                break;
101
            case QrCode::FILE_FORMAT_PNG:
102
            default:
103
                $format = QrCode::FILE_FORMAT_PNG;
104
                $method = "Image";
105
        }
106
107
        $yPosQrCode = 209.5 + $this->offsetY;
108
        $xPosQrCode = self::RIGHT_PART_X + 1 + $this->offsetX;
109
110
        $qrCode->setWriterByExtension($format);
111
        $img = base64_decode(preg_replace('#^data:image/[^;]+;base64,#', '', $qrCode->writeDataUri()));
112
        $this->tcPdf->$method("@" . $img, $xPosQrCode, $yPosQrCode, 46, 46);
113
    }
114
115
    private function addInformationContentReceipt(): void
116
    {
117
        $x = self::LEFT_PART_X;
118
        $this->tcPdf->setCellHeightRatio(self::LEFT_CELL_HEIGHT_RATIO_COMMON);
119
120
        // Title
121
        $this->tcPdf->SetFont($this->font, 'B', self::FONT_SIZE_MAIN_TITLE);
122
        $this->SetY(self::TITLE_Y);
123
        $this->SetX($x);
124
        $this->printCell(Translation::get('receipt', $this->language), 0, 7);
125
126
        // Elements
127
        $this->SetY(204);
128
        foreach ($this->getInformationElementsOfReceipt() as $informationElement) {
129
            $this->SetX($x);
130
            $this->setContentElement($informationElement, true);
131
        }
132
133
        // Acceptance section
134
        $this->tcPdf->SetFont($this->font, 'B', 6);
135
        $this->SetY(273);
136
        $this->SetX($x);
137
        $this->printCell(Translation::get('acceptancePoint', $this->language), 54, 0, self::ALIGN_BELOW, self::ALIGN_RIGHT);
138
    }
139
140
    private function addInformationContent(): void
141
    {
142
        $x = self::RIGHT_PART_X_INFO;
143
        $this->tcPdf->setCellHeightRatio(self::RIGHT_CELL_HEIGHT_RATIO_COMMON);
144
145
        // Title
146
        $this->tcPdf->SetFont($this->font, 'B', self::FONT_SIZE_MAIN_TITLE);
147
        $this->SetY(self::TITLE_Y);
148
        $this->SetX(self::RIGHT_PART_X);
149
        $this->printCell(Translation::get('paymentPart', $this->language), 48, 7);
150
151
        // Elements
152
        $this->SetY(197);
153
        foreach ($this->getInformationElements() as $informationElement) {
154
            $this->SetX($x);
155
            $this->setContentElement($informationElement, false);
156
        }
157
    }
158
159
    private function addCurrencyContentReceipt(): void
160
    {
161
        $x = self::LEFT_PART_X;
162
        $this->tcPdf->setCellHeightRatio(self::LEFT_CELL_HEIGHT_RATIO_CURRENCY_AMOUNT);
163
        $this->SetY(self::CURRENCY_AMOUNT_Y);
164
165
        foreach ($this->getCurrencyElements() as $currencyElement) {
166
            $this->SetX($x);
167
            $this->setContentElement($currencyElement, true);
168
        }
169
    }
170
171
    private function addAmountContentReceipt(): void
172
    {
173
        $x = 16;
174
        $this->tcPdf->setCellHeightRatio(self::LEFT_CELL_HEIGHT_RATIO_CURRENCY_AMOUNT);
175
        $this->SetY(self::CURRENCY_AMOUNT_Y);
176
177
        foreach ($this->getAmountElementsReceipt() as $amountElement) {
178
            $this->SetX($x);
179
            $this->setContentElement($amountElement, true);
180
        }
181
    }
182
183
    private function addCurrencyContent(): void
184
    {
185
        $x = self::RIGHT_PART_X;
186
        $this->tcPdf->setCellHeightRatio(self::RIGHT_CELL_HEIGHT_RATIO_CURRENCY_AMOUNT);
187
        $this->SetY(self::CURRENCY_AMOUNT_Y);
188
189
        foreach ($this->getCurrencyElements() as $currencyElement) {
190
            $this->SetX($x);
191
            $this->setContentElement($currencyElement, false);
192
        }
193
    }
194
195
    private function addAmountContent(): void
196
    {
197
        $x = 80;
198
        $this->tcPdf->setCellHeightRatio(self::RIGHT_CELL_HEIGHT_RATIO_CURRENCY_AMOUNT);
199
        $this->SetY(self::CURRENCY_AMOUNT_Y);
200
201
        foreach ($this->getAmountElements() as $amountElement) {
202
            $this->SetX($x);
203
            $this->setContentElement($amountElement, false);
204
        }
205
    }
206
207
    private function addFurtherInformationContent(): void
208
    {
209
        $x = self::RIGHT_PART_X;
210
        $this->tcPdf->setCellHeightRatio(self::RIGHT_CELL_HEIGHT_RATIO_COMMON);
211
        $this->SetY(286);
212
        $this->tcPdf->SetFont($this->font, '', self::FONT_SIZE_FURTHER_INFORMATION);
213
214
        foreach ($this->getFurtherInformationElements() as $furtherInformationElement) {
215
            $this->SetX($x);
216
            $this->setContentElement($furtherInformationElement, true);
217
        }
218
    }
219
220
    private function addSeparatorContentIfNotPrintable(): void
221
    {
222
        if (!$this->isPrintable()) {
223
            $this->tcPdf->SetLineStyle(['width' => 0.1, 'color' => [0, 0, 0]]);
224
            $this->printLine(2, 193, 208, 193);
225
            $this->printLine(62, 193, 62, 296);
226
            $this->tcPdf->SetFont($this->font, '', self::FONT_SIZE_FURTHER_INFORMATION);
227
            $this->SetY(188);
228
            $this->SetX(5);
229
            $this->printCell(Translation::get('separate', $this->language), 200, 0, 0, self::ALIGN_CENTER);
230
        }
231
    }
232
233
    private function setContentElement(OutputElementInterface $element, bool $isReceiptPart): void
234
    {
235
        if ($element instanceof Title) {
236
            $this->setTitleElement($element, $isReceiptPart);
237
        }
238
239
        if ($element instanceof Text) {
240
            $this->setTextElement($element, $isReceiptPart);
241
        }
242
243
        if ($element instanceof Placeholder) {
244
            $this->setPlaceholderElement($element);
245
        }
246
    }
247
248
    private function setTitleElement(Title $element, bool $isReceiptPart): void
249
    {
250
        $this->tcPdf->SetFont(
251
            $this->font,
252
            'B',
253
            $isReceiptPart ? self::FONT_SIZE_TITLE_RECEIPT : self::FONT_SIZE_TITLE_PAYMENT_PART
254
        );
255
        $this->printCell(
256
            Translation::get(str_replace("text.", "", $element->getTitle()), $this->language),
257
            0,
258
            0,
259
            self::ALIGN_BELOW
260
        );
261
    }
262
263
    private function setTextElement(Text $element, bool $isReceiptPart): void
264
    {
265
        $this->tcPdf->SetFont(
266
            $this->font,
267
            '',
268
            $isReceiptPart ? self::FONT_SIZE_RECEIPT : self::FONT_SIZE_PAYMENT_PART
269
        );
270
271
        $this->printMultiCell(
272
            str_replace("text.", "", $element->getText()),
273
            $isReceiptPart ? 54 : 0,
274
            0,
275
            self::ALIGN_BELOW,
276
            self::ALIGN_LEFT
277
        );
278
        $this->tcPdf->Ln($isReceiptPart ? self::LINE_SPACING_RECEIPT : self::LINE_SPACING_PAYMENT_PART);
279
    }
280
281
    private function setPlaceholderElement(Placeholder $element): void
282
    {
283
        $type = $element->getType();
284
285
        switch ($type) {
286
            case Placeholder::PLACEHOLDER_TYPE_AMOUNT['type']:
287
                $y = $this->tcPdf->GetY() + 1;
288
                $x = $this->tcPdf->GetX() - 2;
289
                break;
290
            case Placeholder::PLACEHOLDER_TYPE_AMOUNT_RECEIPT['type']:
291
                $y = $this->tcPdf->GetY() - 2;
292
                $x = $this->tcPdf->GetX() + 11;
293
                break;
294
            case Placeholder::PLACEHOLDER_TYPE_PAYABLE_BY['type']:
295
            case Placeholder::PLACEHOLDER_TYPE_PAYABLE_BY_RECEIPT['type']:
296
            default:
297
                $y = $this->tcPdf->GetY() + 1;
298
                $x = $this->tcPdf->GetX() + 1;
299
        }
300
301
        $this->tcPdf->ImageSVG(
302
            $element->getFile(),
303
            $x,
304
            $y,
305
            $element->getWidth(),
306
            $element->getHeight()
307
        );
308
    }
309
310
    private function setX(int $x): void
311
    {
312
        $this->tcPdf->SetX($x + $this->offsetX);
313
    }
314
315
    private function setY(int $y): void
316
    {
317
        $this->tcPdf->SetY($y + $this->offsetY);
318
    }
319
320
    private function printCell(
321
        string $text,
322
        int $w = 0,
323
        int $h = 0,
324
        int $nextLineAlign = 0,
325
        string $textAlign = self::ALIGN_LEFT
326
    ): void {
327
        $this->tcPdf->Cell($w, $h, $text, self::BORDER, $nextLineAlign, $textAlign);
328
    }
329
330
    private function printMultiCell(
331
        string $text,
332
        int $w = 0,
333
        int $h = 0,
334
        int $nextLineAlign = 0,
335
        string $textAlign = self::ALIGN_LEFT
336
    ): void {
337
        $this->tcPdf->MultiCell($w, $h, $text, self::BORDER, $textAlign, false, $nextLineAlign);
338
    }
339
340
    private function printLine(int $x1, int $y1, int $x2, int $y2): void
341
    {
342
        $this->tcPdf->Line($x1 + $this->offsetX, $y1 + $this->offsetY, $x2 + $this->offsetX, $y2 + $this->offsetY);
343
    }
344
345
    public function getFont(): string
346
    {
347
        return $this->font;
348
    }
349
350
    public function setFont(string $font): void
351
    {
352
        $this->font = $font;
353
    }
354
}
355