Test Failed
Push — master ( 50ebf9...195aca )
by Gabriel
12:00 queued 12s
created

PdfLetterTrait::addFieldsToPDF()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.032

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 4
cts 5
cp 0.8
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2.032
1
<?php
2
3
namespace ByTIC\DocumentGenerator\PdfLetters;
4
5
use ByTIC\DocumentGenerator\Helpers;
6
use ByTIC\DocumentGenerator\PdfLetters\Fields\FieldTrait;
7
use ByTIC\MediaLibrary\Exceptions\FileCannotBeAdded\FileUnacceptableForCollection;
8
use ByTIC\MediaLibrary\HasMedia\HasMediaTrait;
9
use ByTIC\MediaLibrary\HasMedia\Interfaces\HasMedia;
10
use ByTIC\MediaLibrary\Media\Media;
11
use ByTIC\MediaLibrary\MediaRepository\MediaRepository;
12
use Nip\Records\Traits\AbstractTrait\RecordTrait as AbstractRecordTrait;
13
use setasign\Fpdi;
14
use Symfony\Component\HttpFoundation\File\UploadedFile;
15
use TCPDF;
16
17
/**
18
 * Class PdfLetterTrait
19
 * @package ByTIC\DocumentGenerator\PdfLetters
20
 *
21
 * @method FieldTrait[] getCustomFields()
22
 *
23
 * @property int $id_item
24
 * @property string $type
25
 * @property string $orientation
26
 * @property string $format
27
 */
28
trait PdfLetterTrait
29
{
30
    use AbstractRecordTrait;
31
    use HasMediaTrait;
32
33
    /**
34
     * @return string
35
     */
36
    public function getName()
37
    {
38
        return $this->getManager()->getLabel('title.singular') . ' #' . $this->id;
39
    }
40
41
    /**
42
     * @return bool
43
     */
44
    public function hasFile()
45
    {
46
        $file = $this->getFile();
47
48
        return $file instanceof Media;
49
    }
50
51
    /**
52
     * @return bool|Media
53
     */
54 1
    public function getFile()
55
    {
56 1
        $files = $this->getFiles();
57 1
        if (count($files) < 1) {
58
            return false;
59
        }
60
61 1
        return $files->getDefaultMedia();
62
    }
63
64
    /**
65
     * @return mixed
66
     */
67
    public function delete()
68
    {
69
        $this->deleteLetters();
70
71
        /** @noinspection PhpUndefinedClassInspection */
72
        return parent::delete();
73
    }
74
75
    public function deleteLetters()
76
    {
77
        $this->getFiles()->delete();
78
    }
79
80
    public function downloadExample()
81
    {
82
        $result = $this->getModelExample();
83
        /** @noinspection PhpUndefinedFieldInspection */
84
        $result->demo = true;
0 ignored issues
show
Bug introduced by
The property demo does not seem to exist in Nip\Records\Traits\AbstractTrait\RecordTrait.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
85
86
        $this->download($result);
87
    }
88
89
    /**
90
     * @return AbstractRecordTrait
0 ignored issues
show
Comprehensibility Bug introduced by
The return type AbstractRecordTrait is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?

In PHP traits cannot be used for type-hinting as they do not define a well-defined structure. This is because any class that uses a trait can rename that trait’s methods.

If you would like to return an object that has a guaranteed set of methods, you could create a companion interface that lists these methods explicitly.

Loading history...
91
     */
92
    abstract public function getModelExample();
93
94
    /**
95
     * @param AbstractRecordTrait $model
0 ignored issues
show
introduced by
The type AbstractRecordTrait for parameter $model is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?
Loading history...
96
     */
97
    public function download($model)
98
    {
99
        $pdf = $this->generatePdfObj($model);
100
101
        $pdf->Output($this->getFileNameFromModel($model) . '.pdf', 'D');
102
        die();
103
    }
104
105
    public function downloadBlank()
106
    {
107
        $file = $this->getFile();
108
        $model = $this->getModelExample();
109
        $name = $this->getFileNameFromModel($model) . '.pdf';
110
111
        header('Content-Type: application/pdf');
112
        header('Content-Description: File Transfer');
113
        header('Cache-Control: private, must-revalidate, post-check=0, pre-check=0, max-age=1');
114
        header('Pragma: public');
115
        header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
116
        header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
117
        header('Content-Disposition: attachment; filename="' . $name . '";');
118
        header("Content-Transfer-Encoding: Binary");
119
        echo $file->read();
120
        die();
121
    }
122
123
    /**
124
     * @param $model
125
     * @param $output
126
     * @return bool|Fpdi|TCPDF
127
     */
128 1
    public function generateFile($model, $output = null)
129
    {
130 1
        $pdf = $this->generatePdfObj($model);
131
132 1
        if ($model->demo === true) {
133
            $this->pdfDrawGuidelines($pdf);
134
        }
135 1
        $fileName = $this->getFileNameFromModel($model) . '.pdf';
136 1
        if (is_string($output) && is_dir($output)) {
137
            return $pdf->Output($output . $fileName, 'F');
138
        }
139 1
        if ($output instanceof HasMedia) {
140
            /** @var HasMediaTrait $output */
141 1
            $output->addFileFromContent(
142 1
                $pdf->Output($fileName, 'S'),
143 1
                $fileName
144
            );
145
        }
146 1
        return $pdf;
147
    }
148
149
    /**
150
     * @param AbstractRecordTrait $model
0 ignored issues
show
introduced by
The type AbstractRecordTrait for parameter $model is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?
Loading history...
151
     * @return FPDI|TCPDF
152
     */
153 1
    public function generatePdfObj($model)
154
    {
155 1
        $pdf = $this->generateNewPdfObj();
156
157
        /** @noinspection PhpUndefinedFieldInspection */
158 1
        if ($model->demo === true) {
0 ignored issues
show
Bug introduced by
The property demo does not seem to exist in Nip\Records\Traits\AbstractTrait\RecordTrait.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
159
            $this->pdfDrawGuidelines($pdf);
160
        }
161
162 1
        $this->addFieldsToPDF($pdf, $model);
163
164 1
        return $pdf;
165
    }
166
167
    /**
168
     * @param $pdf
169
     * @param $model
170
     */
171 1
    protected function addFieldsToPDF($pdf, $model)
172
    {
173
174
        /** @var FieldTrait[] $fields */
175 1
        $fields = $this->getCustomFields();
176 1
        foreach ($fields as $field) {
177
            $field->addToPdf($pdf, $model);
178
        }
179 1
    }
180
181
    /**
182
     * @return Fpdi\Tcpdf\Fpdi|TCPDF
183
     * @throws Fpdi\PdfParser\CrossReference\CrossReferenceException
184
     * @throws Fpdi\PdfParser\Filter\FilterException
185
     * @throws Fpdi\PdfParser\PdfParserException
186
     * @throws Fpdi\PdfParser\Type\PdfTypeException
187
     * @throws Fpdi\PdfReader\PdfReaderException
188
     */
189 1
    public function generateNewPdfObj()
190
    {
191 1
        $pdf = static::newPdfBuilder('L');
192
193 1
        $mediaFile = $this->getFile();
194 1
        $pageCount = $pdf->setSourceFile($mediaFile->getFile()->readStream());
195 1
        for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
196 1
            $tplidx = $pdf->importPage($pageNo, '/MediaBox');
197
198 1
            $pdf->AddPage(ucfirst($this->orientation), $this->format);
199 1
            $pdf->useTemplate($tplidx);
200 1
            $pdf->endPage();
201
        }
202 1
        $pdf->setPage(1);
203
204 1
        return $pdf;
205
    }
206
207
    /**
208
     * @param mixed ...$params
209
     * @return Fpdi\Tcpdf\Fpdi
210
     */
211 2
    public static function newPdfBuilder(...$params)
212
    {
213 2
        $pdf = new Fpdi\Tcpdf\Fpdi(...$params);
214 2
        $pdf->setPrintHeader(false);
215 2
        $pdf->SetCreator(PDF_CREATOR);
216 2
        $pdf->SetAuthor(Helpers::author());
217
218 2
        return $pdf;
219
    }
220
221
    /**
222
     * @return AbstractRecordTrait
0 ignored issues
show
Comprehensibility Bug introduced by
The return type AbstractRecordTrait is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?

In PHP traits cannot be used for type-hinting as they do not define a well-defined structure. This is because any class that uses a trait can rename that trait’s methods.

If you would like to return an object that has a guaranteed set of methods, you could create a companion interface that lists these methods explicitly.

Loading history...
223
     */
224
    public function getItem()
225
    {
226
        $manager = $this->getItemsManager();
227
228
        return $manager->findOne($this->id_item);
0 ignored issues
show
Bug introduced by
It seems like findOne() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
229
    }
230
231
    /**
232
     * @return AbstractRecordTrait
0 ignored issues
show
Comprehensibility Bug introduced by
The return type AbstractRecordTrait is a trait, and thus cannot be used for type-hinting in PHP. Maybe consider adding an interface and use that for type-hinting?

In PHP traits cannot be used for type-hinting as they do not define a well-defined structure. This is because any class that uses a trait can rename that trait’s methods.

If you would like to return an object that has a guaranteed set of methods, you could create a companion interface that lists these methods explicitly.

Loading history...
233
     */
234
    abstract public function getItemsManager();
235
236
    /**
237
     * @return string
238
     */
239 1
    protected function getFileNameDefault()
240
    {
241 1
        return 'letter';
242
    }
243
244
    /**
245
     * @param FPDI|TCPDF $pdf
246
     */
247
    protected function pdfDrawGuidelines($pdf)
248
    {
249
        for ($pos = 5; $pos < 791; $pos = $pos + 5) {
250
            if (($pos % 100) == 0) {
251
                $pdf->SetDrawColor(0, 0, 200);
252
                $pdf->SetLineWidth(.7);
253
            } elseif (($pos % 50) == 0) {
254
                $pdf->SetDrawColor(200, 0, 0);
255
                $pdf->SetLineWidth(.4);
256
            } else {
257
                $pdf->SetDrawColor(128, 128, 128);
258
                $pdf->SetLineWidth(.05);
259
            }
260
261
            $pdf->Line(0, $pos, 611, $pos);
262
            if ($pos < 611) {
263
                $pdf->Line($pos, 0, $pos, 791);
264
            }
265
        }
266
    }
267
268
    /** @noinspection PhpUnusedParameterInspection
269
     * @param $model
270
     * @return string
271
     */
272 1
    protected function getFileNameFromModel($model)
0 ignored issues
show
Unused Code introduced by
The parameter $model is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
273
    {
274 1
        return $this->getFileNameDefault();
275
    }
276
277
    /**
278
     * @param UploadedFile $uploadedFile
279
     * @return string|boolean
280
     */
281
    public function uploadFromRequest($uploadedFile)
282
    {
283
        $fileCollection = $this->getFiles();
284
285
        if (!$uploadedFile->isValid()) {
286
            return $uploadedFile->getErrorMessage();
287
        }
288
289
        try {
290
            $fileAdder = $this->addFile($uploadedFile);
291
            $newMedia = $fileAdder->getMedia();
292
        } catch (FileUnacceptableForCollection $exception) {
293
            return $exception->violations->getMessageString();
294
        }
295
296
        foreach ($fileCollection as $name => $media) {
297
            if ($name != $newMedia->getName()) {
298
                $media->delete();
299
            }
300
        }
301
        return $newMedia;
302
    }
303
304
    /**
305
     * @param MediaRepository $mediaRepository
306
     * @return MediaRepository
307
     */
308 1
    protected function hydrateMediaRepositoryCustom($mediaRepository)
309
    {
310 1
        $filesCollection = $mediaRepository->getCollection('files');
311 1
        $filesCollection->getConstraint()->mimeTypes = ['application/pdf'];
312 1
        return $mediaRepository;
313
    }
314
}
315