PdfFusionLaravel::__destruct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
namespace Doode\PdfFusionLaravel;
3
use setasign\Fpdi\Fpdi;
4
use Illuminate\Filesystem\Filesystem;
0 ignored issues
show
Bug introduced by
The type Illuminate\Filesystem\Filesystem was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
5
use Illuminate\Support\Collection;
0 ignored issues
show
Bug introduced by
The type Illuminate\Support\Collection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use Illuminate\Support\Str;
0 ignored issues
show
Bug introduced by
The type Illuminate\Support\Str was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
8
class PdfFusionLaravel {
9
	/**
10
	 * Access the filesystem on an oop base
11
	 *
12
	 * @var Filesystem
13
	 */
14
	protected $filesystem = Filesystem::class;
15
	/**
16
	 * Hold all the files which will be merged
17
	 *
18
	 * @var Collection
19
	 */
20
	protected $files = Collection::class;
21
	/**
22
	 * Holds every tmp file so they can be removed during the deconstruction
23
	 *
24
	 * @var Collection
25
	 */
26
	protected $tmpFiles = Collection::class;
27
	/**
28
	 * The actual PDF Service
29
	 *
30
	 * @var FPDI
31
	 */
32
	protected $fpdi = Fpdi::class;
33
	/**
34
	 * The final file name
35
	 *
36
	 * @var string
37
	 */
38
	protected $fileName = 'undefined.pdf';
39
	/**
40
	 * Construct and initialize a new instance
41
	 * @param Filesystem $Filesystem
42
	 */
43
	public function __construct(Filesystem $filesystem){
44
		$this->filesystem = $filesystem;
45
		$this->createDirectoryForTemporaryFiles();
46
		$this->fpdi = new Fpdi();
47
		$this->tmpFiles = collect([]);
0 ignored issues
show
Bug introduced by
The function collect was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

47
		$this->tmpFiles = /** @scrutinizer ignore-call */ collect([]);
Loading history...
48
		$this->files = collect([]);
49
	}
50
	/**
51
	 * The class deconstructor method
52
	 */
53
	public function __destruct() {
54
		$filesystem = $this->filesystem;
55
		$this->tmpFiles->each(function($filePath) use($filesystem){
56
			$filesystem->delete($filePath);
57
		});
58
	}
59
	/**
60
	 * Initialize a new internal instance of FPDI in order to prevent any problems with shared resources
61
	 * Please visit https://www.setasign.com/products/fpdi/manual/#p-159 for more information on this issue
62
	 *
63
	 * @return self
64
	 */
65
	public function init(){
66
		return $this;
67
	}
68
	/**
69
	 * Stream the merged PDF content
70
	 *
71
	 * @return string
72
	 */
73
	public function inline(){
74
		return $this->fpdi->Output($this->fileName, 'I');
75
	}
76
	/**
77
	 * Download the merged PDF content
78
	 *
79
	 * @return string
80
	 */
81
	public function download(){
82
		return $this->fpdi->Output($this->fileName, 'D');
83
	}
84
	/**
85
	 * Save the merged PDF content to the filesystem
86
	 *
87
	 * @return string
88
	 */
89
	public function save($filePath = null){
90
		return $this->filesystem->put($filePath ? $filePath : $this->fileName, $this->string());
91
	}
92
	/**
93
	 * Get the merged PDF content as binary string
94
	 *
95
	 * @return string
96
	 */
97
	public function string(){
98
		return $this->fpdi->Output($this->fileName, 'S');
99
	}
100
	/**
101
	 * Set the generated PDF fileName
102
	 * @param string $fileName
103
	 *
104
	 * @return string
105
	 */
106
	public function setFileName($fileName){
107
		$this->fileName = $fileName;
108
		return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Doode\PdfFusionLaravel\PdfFusionLaravel which is incompatible with the documented return type string.
Loading history...
109
	}
110
	/**
111
	 * Add a PDF for inclusion in the merge with a binary string. Pages should be formatted: 1,3,6, 12-16.
112
	 * @param string $string
113
	 * @param mixed $pages
114
	 * @param mixed $orientation
115
	 *
116
	 * @return void
117
	 */
118
	public function addPDFString($string, $pages = 'all', $orientation = null){
119
		$filePath = storage_path('tmp/'.Str::random(16).'.pdf');
0 ignored issues
show
Bug introduced by
The function storage_path was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

119
		$filePath = /** @scrutinizer ignore-call */ storage_path('tmp/'.Str::random(16).'.pdf');
Loading history...
120
		$this->filesystem->put($filePath, $string);
121
		$this->tmpFiles->push($filePath);
122
		return $this->addPathToPDF($filePath, $pages, $orientation);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->addPathToP..., $pages, $orientation) returns the type Doode\PdfFusionLaravel\PdfFusionLaravel which is incompatible with the documented return type void.
Loading history...
123
	}
124
	/**
125
	 * Add a PDF for inclusion in the merge with a valid file path. Pages should be formatted: 1,3,6, 12-16.
126
	 * @param string $filePath
127
	 * @param string $pages
128
	 * @param string $orientation
129
	 *
130
	 * @return self
131
	 *
132
	 * @throws \Exception if the given pages aren't correct
133
	 */
134
	public function addPathToPDF($filePath, $pages = 'all', $orientation = null) {
135
		if (file_exists($filePath)) {
136
		$filePath = $this->convertPDFVersion($filePath);
137
		if (!is_array($pages) && strtolower($pages) != 'all') {
0 ignored issues
show
introduced by
The condition is_array($pages) is always false.
Loading history...
138
			throw new \Exception($filePath."'s pages could not be validated");
139
		}
140
		$this->files->push([
141
			'name'  => $filePath,
142
			'pages' => $pages,
143
			'orientation' => $orientation
144
		]);
145
		} else {
146
			throw new \Exception("Could not locate PDF on '$filePath'");
147
		}
148
		return $this;
149
	}
150
	/**
151
	 * Merges your provided PDFs and outputs to specified location.
152
	 * @param string $orientation
153
	 *
154
	 * @return void
155
	 *
156
	 * @throws \Exception if there are now PDFs to merge
157
	 */
158
	public function duplexMerge($orientation = 'P'){
159
		$this->merge($orientation, true);
160
	}
161
162
	public function merge($orientation = 'P', $duplex = false) {
163
		if ($this->files->count() == 0) {
164
			throw new \Exception("No PDFs to merge.");
165
		}
166
		$fpdi = $this->fpdi;
167
		$files = $this->files;
168
		foreach($files as $index => $file){
169
			$file['orientation'] = is_null($file['orientation']) ? $orientation : $file['orientation'];
170
			$count = $fpdi->setSourceFile($file['name']);
171
			if($file['pages'] == 'all') {
172
				$pages = $count;
173
				for ($i = 1; $i <= $count; $i++) {
174
					$template   = $fpdi->importPage($i);
175
					$size       = $fpdi->getTemplateSize($template);
176
					$fpdi->AddPage($file['orientation'], [$size['width'], $size['height']]);
177
					$fpdi->useTemplate($template);
178
				}
179
			}else {
180
				$pages = count($file['pages']);
181
				foreach ($file['pages'] as $page) {
182
					if (!$template = $fpdi->importPage($page)) {
183
					throw new \Exception("Could not load page '$page' in PDF '".$file['name']."'. Check that the page exists.");
184
					}
185
					$size = $fpdi->getTemplateSize($template);
186
					$fpdi->AddPage($file['orientation'], [$size['width'], $size['height']]);
187
					$fpdi->useTemplate($template);
188
				}
189
			}
190
			if ($duplex && $pages % 2 && $index < (count($files) - 1)) {
191
				$fpdi->AddPage($file['orientation'], [$size['width'], $size['height']]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $size does not seem to be defined for all execution paths leading up to this point.
Loading history...
192
			}
193
		}
194
	}
195
196
	/**
197
	 * Converts PDF if version is above 1.4
198
	 * @param string $filePath
199
	 *
200
	 * @return string
201
	 */
202
	protected function convertPDFVersion($filePath){
203
		$pdf = fopen($filePath, "r");
204
		$first_line = fgets($pdf);
0 ignored issues
show
Bug introduced by
It seems like $pdf can also be of type false; however, parameter $handle of fgets() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

204
		$first_line = fgets(/** @scrutinizer ignore-type */ $pdf);
Loading history...
205
		fclose($pdf);
0 ignored issues
show
Bug introduced by
It seems like $pdf can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

205
		fclose(/** @scrutinizer ignore-type */ $pdf);
Loading history...
206
		//extract version number
207
		preg_match_all('!\d+!', $first_line, $matches);
208
		$pdfversion = implode('.', $matches[0]);
209
		if($pdfversion > "1.4"){
210
			$newFilePath = storage_path('tmp/' . Str::random(16) . '.pdf');
0 ignored issues
show
Bug introduced by
The function storage_path was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

210
			$newFilePath = /** @scrutinizer ignore-call */ storage_path('tmp/' . Str::random(16) . '.pdf');
Loading history...
211
			//execute shell script that converts PDF to correct version and saves it to tmp folder
212
			shell_exec('gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile="'. $newFilePath . '" "' . $filePath . '"');
213
			$this->tmpFiles->push($newFilePath);
214
			$filePath = $newFilePath;
215
		}
216
		//return correct file path
217
		return $filePath;
218
	}
219
220
	/**
221
	 * Create a the temporary file directory if it doesn't exist.
222
	 *
223
	 * @return void
224
	 */
225
	protected function createDirectoryForTemporaryFiles(): void
226
	{
227
		if (! $this->filesystem->isDirectory(storage_path('tmp'))) {
0 ignored issues
show
Bug introduced by
The function storage_path was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

227
		if (! $this->filesystem->isDirectory(/** @scrutinizer ignore-call */ storage_path('tmp'))) {
Loading history...
228
			$this->filesystem->makeDirectory(storage_path('tmp'));
229
		}
230
	}
231
}
232