Passed
Pull Request — master (#59)
by Franco
03:35
created

FpdfOutput::setPlaceholderElement()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 26
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

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