Test Failed
Pull Request — master (#59)
by
unknown
02:58
created

FpdfOutput::getPngImage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 10
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
        $this->addSeparatorContentIfNotPrintable();
70
        $this->addReceiptPart();
71
        $this->addPaymentPart();
72
    }
73
74
    public function setQrCodeImageFormat(string $fileExtension): self
75
    {
76
        $this->qrCodeImageFormat = $fileExtension;
77
        if ($fileExtension === 'svg') {
78
            throw new InvalidFpdfImageFormat('SVG images are not allowed by FPDF.');
79
        }
80
        return $this;
81
    }
82
83
    private function addSeparatorContentIfNotPrintable()
84
    {
85
        if (!$this->isPrintable()) {
86
            $this->fpdf->SetLineWidth(0.1);
87
            $this->fpdf->Line(2, 193, 208, 193);
88
            $this->fpdf->Line(62, 193, 62, 296);
89
            $this->fpdf->SetFont(self::FPDF_FONT, '', 7);
90
            $this->SetY(189.6);
91
            $this->fpdf->MultiCell(0, 0, utf8_decode(Translation::get('separate', $this->language)), self::FPDF_BORDER, self::FPDF_ALIGN_CENTER);
92
        }
93
    }
94
95
    private function addReceiptPart()
96
    {
97
        // Title
98
        $this->fpdf->SetFont(self::FPDF_FONT, 'B', 11);
99
        $this->SetXY(self::FPDF_LEFT_PART_X, self::FPDF_TITLE_Y);
100
        $this->fpdf->MultiCell(0, 7, utf8_decode(Translation::get('receipt', $this->language)));
101
102
        // Elements
103
        $this->SetY(204);
104
        foreach ($this->getInformationElementsOfReceipt() as $receiptInformationElement) {
105
            $this->SetX(self::FPDF_LEFT_PART_X);
106
            $this->setContentElement($receiptInformationElement, true);
107
        }
108
109
        // Amount
110
        $this->SetY(self::FPDF_CURRENCY_AMOUNT_Y);
111
        foreach ($this->getCurrencyElements() as $receiptCurrencyElement) {
112
            $this->amountLS = self::FPDF_AMOUNT_LINE_SPACING_RCPT;
113
            $this->SetX(self::FPDF_LEFT_PART_X);
114
            $this->setContentElement($receiptCurrencyElement, true);
115
            $this->amountLS = 0;
116
        }
117
        $this->SetY(self::FPDF_CURRENCY_AMOUNT_Y);
118
        foreach ($this->getAmountElementsReceipt() as $receiptAmountElement) {
119
            $this->amountLS = self::FPDF_AMOUNT_LINE_SPACING_RCPT;
120
            $this->SetX(16);
121
            $this->setContentElement($receiptAmountElement, true);
122
            $this->amountLS = 0;
123
        }
124
125
        // Acceptance section
126
        $this->fpdf->SetFont(self::FPDF_FONT, 'B', 6);
127
        $this->SetXY(self::FPDF_LEFT_PART_X, 274.3);
128
        $this->fpdf->Cell(54, 0, utf8_decode(Translation::get('acceptancePoint', $this->language)), self::FPDF_BORDER, '', self::FPDF_ALIGN_RIGHT);
129
    }
130
131
    private function addPaymentPart()
132
    {
133
        // Title
134
        $this->fpdf->SetFont(self::FPDF_FONT, 'B', 11);
135
        $this->SetXY(self::FPDF_RIGHT_PART_X, 195.2);
136
        $this->fpdf->MultiCell(48, 7, utf8_decode(Translation::get('paymentPart', $this->language)));
137
138
        // QRCode
139
        $image = $this->getPngImage();
140
        $this->fpdf->Image($image[0], 67, 209.5, 46, 46, $image[1]);
141
142
        // Information Section
143
        $this->SetY(197.3);
144
        foreach ($this->getInformationElements() as $informationElement) {
145
            $this->SetX(self::FPDF_RIGHT_PAR_X_INFO);
146
            $this->setContentElement($informationElement, false);
147
        }
148
149
        // Amount section
150
        $this->SetY(self::FPDF_CURRENCY_AMOUNT_Y);
151
        foreach ($this->getCurrencyElements() as $currencyElement) {
152
            $this->amountLS = self::FPDF_AMOUNT_LINE_SPACING;
153
            $this->SetX(self::FPDF_RIGHT_PART_X);
154
            $this->setContentElement($currencyElement, false);
155
            $this->amountLS = 0;
156
        }
157
        $this->SetY(self::FPDF_CURRENCY_AMOUNT_Y);
158
        foreach ($this->getAmountElements() as $amountElement) {
159
            $this->amountLS = self::FPDF_AMOUNT_LINE_SPACING;
160
            $this->SetX(80);
161
            $this->setContentElement($amountElement, false);
162
            $this->amountLS = 0;
163
        }
164
165
        // Further Information Section
166
        $this->SetY(286);
167
        $this->fpdf->SetFont(self::FPDF_FONT, '', 7);
168
        foreach ($this->getFurtherInformationElements() as $furtherInformationElement) {
169
            $this->SetX(self::FPDF_RIGHT_PART_X);
170
            $this->setContentElement($furtherInformationElement, true);
171
        }
172
    }
173
174
    private function setContentElement(OutputElementInterface $element, bool $isReceiptPart): void
175
    {
176
        if ($element instanceof Title) {
177
            $this->setTitleElement($element, $isReceiptPart);
178
        }
179
180
        if ($element instanceof Text) {
181
            $this->setTextElement($element, $isReceiptPart);
182
        }
183
184
        if ($element instanceof Placeholder) {
185
            $this->setPlaceholderElement($element);
186
        }
187
    }
188
189
    private function setTitleElement(Title $element, bool $isReceiptPart): void
190
    {
191
        $this->fpdf->SetFont(self::FPDF_FONT, 'B', $isReceiptPart ? 6 : 8);
192
        $this->fpdf->MultiCell(0, 2.8, utf8_decode(
193
            Translation::get(str_replace("text.", "", $element->getTitle()), $this->language)
194
        ));
195
        $this->fpdf->Ln($this->amountLS);
196
    }
197
198
    private function setTextElement(Text $element, bool $isReceiptPart): void
199
    {
200
        $this->fpdf->SetFont(self::FPDF_FONT, '', $isReceiptPart ? 8 : 10);
201
        $this->fpdf->MultiCell(
202
            $isReceiptPart ? 54 : 0,
203
            $isReceiptPart ? 3.3 : 4,
204
            str_replace("text.", "", utf8_decode($element->getText())),
205
            self::FPDF_BORDER,
206
            self::FPDF_ALIGN_LEFT
207
        );
208
        $this->fpdf->Ln($isReceiptPart ? self::FPDF_9PT : self::FPDF_11PT);
209
    }
210
211
    private function setPlaceholderElement(Placeholder $element): void
212
    {
213
        $type = $element->getType();
214
215
        switch ($type) {
216
            case Placeholder::PLACEHOLDER_TYPE_AMOUNT['type']:
217
                $y = $this->fpdf->GetY() + 1;
218
                $x = $this->fpdf->GetX() - 2;
219
                break;
220
            case Placeholder::PLACEHOLDER_TYPE_AMOUNT_RECEIPT['type']:
221
                $y = $this->fpdf->GetY() - 2;
222
                $x = $this->fpdf->GetX() + 11;
223
                break;
224
            case Placeholder::PLACEHOLDER_TYPE_PAYABLE_BY['type']:
225
            case Placeholder::PLACEHOLDER_TYPE_PAYABLE_BY_RECEIPT['type']:
226
            default:
227
                $y = $this->fpdf->GetY() + 1;
228
                $x = $this->fpdf->GetX() + 1;
229
        }
230
231
        $this->fpdf->Image(
232
            $element->getFile('png'),
233
            $x,
234
            $y,
235
            $element->getWidth(),
236
            $element->getHeight()
237
        );
238
    }
239
240
    private function setX(float $x) : void
241
    {
242
        $this->fpdf->SetX($x + $this->offsetX);
243
    }
244
245
    private function setY(float $y) : void
246
    {
247
        $this->fpdf->SetY($y + $this->offsetY);
248
    }
249
250
    private function SetXY(float $x, float $y) : void
251
    {
252
        $this->fpdf->SetXY($x + $this->offsetX, $y + $this->offsetY);
253
    }
254
255
    private function getPngImage()
256
    {
257
        $qrCode = $this->getQrCode();
258
        $format = QrCode::FILE_FORMAT_PNG;
259
        $qrCode->setWriterByExtension($format);
260
        $image64 = explode(',', $qrCode->writeDataUri(), 2);
261
        $image = 'data://text/plain;base64,' . $image64[1];
262
        $type = 'png';
263
264
        return [$image, $type];
265
    }
266
}
267