Passed
Push — master ( 35512a...efd4a3 )
by Manuel
03:46 queued 12s
created

FpdfOutput::setContentElement()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 6
nc 8
nop 2
dl 0
loc 12
rs 10
c 0
b 0
f 0
1
<?php
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 constants
21
    private const FPDF_BORDER = 0;
22
    private const FPDF_ALIGN_LEFT = 'L';
23
    private const FPDF_ALIGN_RIGHT = 'R';
24
    private const FPDF_ALIGN_CENTER = 'C';
25
    private const FPDF_FONT = 'Helvetica';
26
27
    // Location constants
28
    private const FPDF_CURRENCY_AMOUNT_Y = 259.3;
29
    private const FPDF_AMOUNT_LINE_SPACING = 1.2;
30
    private const FPDF_AMOUNT_LINE_SPACING_RCPT = 0.6;
31
    private const FPDF_LEFT_PART_X = 4;
32
    private const FPDF_RIGHT_PART_X = 66;
33
    private const FPDF_RIGHT_PAR_X_INFO = 117;
34
    private const FPDF_TITLE_Y = 195.2;
35
36
    // Line spacing constants
37
    private const FPDF_9PT = 3.4;
38
    private const FPDF_11PT = 4.8;
39
    
40
    /** @var Fpdf */
41
    private $fpdf;
42
43
    /** @var float */
44
    private $amountLS = 0;
45
46
    /* @var int $offsetX */
47
    private $offsetX;
48
49
    /* @var int $offsetY */
50
    private $offsetY;
51
52
    public function __construct(
53
        QrBill $qrBill,
54
        string $language,
55
        Fpdf $fpdf,
56
        int $offsetX = 0,
57
        int $offsetY = 0
58
    ) {
59
        parent::__construct($qrBill, $language);
60
        $this->fpdf = $fpdf;
61
        $this->offsetX = $offsetX;
62
        $this->offsetY = $offsetY;
63
        $this->setQrCodeImageFormat(QrCode::FILE_FORMAT_PNG);
64
    }
65
66
    public function getPaymentPart()
67
    {
68
        $this->fpdf->SetAutoPageBreak(false);
69
70
        $this->addSeparatorContentIfNotPrintable();
71
72
        $this->addInformationContentReceipt();
73
        $this->addCurrencyContentReceipt();
74
        $this->addAmountContentReceipt();
75
76
        $this->addSwissQrCodeImage();
77
        $this->addInformationContent();
78
        $this->addCurrencyContent();
79
        $this->addAmountContent();
80
        $this->addFurtherInformationContent();
81
    }
82
83
    public function setQrCodeImageFormat(string $fileExtension): AbstractOutput
84
    {
85
        if ($fileExtension === 'svg') {
86
            throw new InvalidFpdfImageFormat('SVG images are not allowed by FPDF.');
87
        }
88
89
        $this->qrCodeImageFormat = $fileExtension;
90
91
        return $this;
92
    }
93
94
    private function addSwissQrCodeImage(): void
95
    {
96
        $qrCode = $this->getQrCode();
97
        $qrCode->setWriterByExtension(
98
            $this->getQrCodeImageFormat()
99
        );
100
101
        $yPosQrCode = 209.5 + $this->offsetY;
102
        $xPosQrCode = 67 + $this->offsetX;
103
104
        $this->fpdf->Image($qrCode->writeDataUri(), $xPosQrCode, $yPosQrCode, 46, 46, 'png');
105
    }
106
107
    private function addInformationContentReceipt(): void
108
    {
109
        // Title
110
        $this->fpdf->SetFont(self::FPDF_FONT, 'B', 11);
111
        $this->SetXY(self::FPDF_LEFT_PART_X, self::FPDF_TITLE_Y);
112
        $this->fpdf->MultiCell(0, 7, utf8_decode(Translation::get('receipt', $this->language)));
113
114
        // Elements
115
        $this->SetY(204);
116
        foreach ($this->getInformationElementsOfReceipt() as $receiptInformationElement) {
117
            $this->SetX(self::FPDF_LEFT_PART_X);
118
            $this->setContentElement($receiptInformationElement, true);
119
        }
120
121
        // Acceptance section
122
        $this->fpdf->SetFont(self::FPDF_FONT, 'B', 6);
123
        $this->SetXY(self::FPDF_LEFT_PART_X, 274.3);
124
        $this->fpdf->Cell(54, 0, utf8_decode(Translation::get('acceptancePoint', $this->language)), self::FPDF_BORDER, '', self::FPDF_ALIGN_RIGHT);
125
    }
126
127
    private function addInformationContent(): void
128
    {
129
        // Title
130
        $this->fpdf->SetFont(self::FPDF_FONT, 'B', 11);
131
        $this->SetXY(self::FPDF_RIGHT_PART_X, 195.2);
132
        $this->fpdf->MultiCell(48, 7, utf8_decode(Translation::get('paymentPart', $this->language)));
133
134
        // Elements
135
        $this->SetY(197.3);
136
        foreach ($this->getInformationElements() as $informationElement) {
137
            $this->SetX(self::FPDF_RIGHT_PAR_X_INFO);
138
            $this->setContentElement($informationElement, false);
139
        }
140
    }
141
142
    private function addCurrencyContentReceipt(): void
143
    {
144
        $this->SetY(self::FPDF_CURRENCY_AMOUNT_Y);
145
        foreach ($this->getCurrencyElements() as $receiptCurrencyElement) {
146
            $this->amountLS = self::FPDF_AMOUNT_LINE_SPACING_RCPT;
147
            $this->SetX(self::FPDF_LEFT_PART_X);
148
            $this->setContentElement($receiptCurrencyElement, true);
149
            $this->amountLS = 0;
150
        }
151
    }
152
153
    private function addAmountContentReceipt(): void
154
    {
155
        $this->SetY(self::FPDF_CURRENCY_AMOUNT_Y);
156
        foreach ($this->getAmountElementsReceipt() as $receiptAmountElement) {
157
            $this->amountLS = self::FPDF_AMOUNT_LINE_SPACING_RCPT;
158
            $this->SetX(16);
159
            $this->setContentElement($receiptAmountElement, true);
160
            $this->amountLS = 0;
161
        }
162
    }
163
164
    private function addCurrencyContent(): void
165
    {
166
        $this->SetY(self::FPDF_CURRENCY_AMOUNT_Y);
167
        foreach ($this->getCurrencyElements() as $currencyElement) {
168
            $this->amountLS = self::FPDF_AMOUNT_LINE_SPACING;
169
            $this->SetX(self::FPDF_RIGHT_PART_X);
170
            $this->setContentElement($currencyElement, false);
171
            $this->amountLS = 0;
172
        }
173
    }
174
175
    private function addAmountContent(): void
176
    {
177
        $this->SetY(self::FPDF_CURRENCY_AMOUNT_Y);
178
        foreach ($this->getAmountElements() as $amountElement) {
179
            $this->amountLS = self::FPDF_AMOUNT_LINE_SPACING;
180
            $this->SetX(80);
181
            $this->setContentElement($amountElement, false);
182
            $this->amountLS = 0;
183
        }
184
    }
185
186
    private function addFurtherInformationContent(): void
187
    {
188
        $this->SetXY(self::FPDF_RIGHT_PART_X, 286);
189
        $this->fpdf->SetFont(self::FPDF_FONT, '', 7);
190
191
        foreach ($this->getFurtherInformationElements() as $furtherInformationElement) {
192
            $this->SetX(self::FPDF_RIGHT_PART_X);
193
            $this->setContentElement($furtherInformationElement, true);
194
        }
195
    }
196
197
    private function addSeparatorContentIfNotPrintable()
198
    {
199
        if (!$this->isPrintable()) {
200
            $this->fpdf->SetLineWidth(0.1);
201
            $this->fpdf->Line(2 + $this->offsetX, 193 + $this->offsetY, 208 + $this->offsetX, 193 + $this->offsetY);
202
            $this->fpdf->Line(62 + $this->offsetX, 193 + $this->offsetY, 62 + $this->offsetX, 296 + $this->offsetY);
203
            $this->fpdf->SetFont(self::FPDF_FONT, '', 7);
204
            $this->SetY(189.6);
205
            $this->fpdf->MultiCell(0, 0, utf8_decode(Translation::get('separate', $this->language)), self::FPDF_BORDER, self::FPDF_ALIGN_CENTER);
206
        }
207
    }
208
209
    private function setContentElement(OutputElementInterface $element, bool $isReceiptPart): void
210
    {
211
        if ($element instanceof Title) {
212
            $this->setTitleElement($element, $isReceiptPart);
213
        }
214
215
        if ($element instanceof Text) {
216
            $this->setTextElement($element, $isReceiptPart);
217
        }
218
219
        if ($element instanceof Placeholder) {
220
            $this->setPlaceholderElement($element);
221
        }
222
    }
223
224
    private function setTitleElement(Title $element, bool $isReceiptPart): void
225
    {
226
        $this->fpdf->SetFont(self::FPDF_FONT, 'B', $isReceiptPart ? 6 : 8);
227
        $this->fpdf->MultiCell(0, 2.8, utf8_decode(
228
            Translation::get(str_replace("text.", "", $element->getTitle()), $this->language)
229
        ));
230
        $this->fpdf->Ln($this->amountLS);
231
    }
232
233
    private function setTextElement(Text $element, bool $isReceiptPart): void
234
    {
235
        $this->fpdf->SetFont(self::FPDF_FONT, '', $isReceiptPart ? 8 : 10);
236
        $this->fpdf->MultiCell(
237
            $isReceiptPart ? 54 : 0,
238
            $isReceiptPart ? 3.3 : 4,
239
            str_replace("text.", "", utf8_decode($element->getText())),
240
            self::FPDF_BORDER,
241
            self::FPDF_ALIGN_LEFT
242
        );
243
        $this->fpdf->Ln($isReceiptPart ? self::FPDF_9PT : self::FPDF_11PT);
244
    }
245
246
    private function setPlaceholderElement(Placeholder $element): void
247
    {
248
        $type = $element->getType();
249
250
        switch ($type) {
251
            case Placeholder::PLACEHOLDER_TYPE_AMOUNT['type']:
252
                $y = $this->fpdf->GetY() + 1;
253
                $x = $this->fpdf->GetX() - 2;
254
                break;
255
            case Placeholder::PLACEHOLDER_TYPE_AMOUNT_RECEIPT['type']:
256
                $y = $this->fpdf->GetY() - 2;
257
                $x = $this->fpdf->GetX() + 11;
258
                break;
259
            case Placeholder::PLACEHOLDER_TYPE_PAYABLE_BY['type']:
260
            case Placeholder::PLACEHOLDER_TYPE_PAYABLE_BY_RECEIPT['type']:
261
            default:
262
                $y = $this->fpdf->GetY() + 1;
263
                $x = $this->fpdf->GetX() + 1;
264
        }
265
266
        $this->fpdf->Image(
267
            $element->getFile(Placeholder::FILE_TYPE_PNG),
268
            $x,
269
            $y,
270
            $element->getWidth(),
271
            $element->getHeight()
272
        );
273
    }
274
275
    private function setX(float $x) : void
276
    {
277
        $this->fpdf->SetX($x + $this->offsetX);
278
    }
279
280
    private function setY(float $y) : void
281
    {
282
        $this->fpdf->SetY($y + $this->offsetY);
283
    }
284
285
    private function SetXY(float $x, float $y) : void
286
    {
287
        $this->fpdf->SetXY($x + $this->offsetX, $y + $this->offsetY);
288
    }
289
}
290