PdfGenerator::getStoragePath()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace PhantomPdf;
4
5
use Exception;
6
use Symfony\Component\Process\Exception\RuntimeException;
7
use Symfony\Component\Process\Process;
8
9
class PdfGenerator
10
{
11
    /**
12
     * @var string
13
     */
14
    protected $baseUrl;
15
16
    /**
17
     * @var string
18
     */
19
    protected $binaryPath = 'phantomjs';
20
21
    /**
22
     * @var string
23
     */
24
    protected $storagePath;
25
26
    /**
27
     * @var string
28
     */
29
    protected $htmlPath;
30
31
    /**
32
     * @var string
33
     */
34
    protected $pdfPath;
35
36
    /**
37
     * @var int
38
     */
39
    protected $timeout = 10;
40
41
    /**
42
     * @var array
43
     */
44
    protected $commandLineOptions = [];
45
46
    /**
47
     * @var string
48
     */
49
    protected $convertScript = 'generate-pdf.js';
50
51
    /**
52
     * @var string
53
     */
54
    protected $orientation = 'portrait';
55
56
    /**
57
     * Save a PDF file to the disk
58
     * @param string|object $view
59
     * @param string $path
60
     */
61 1
    public function saveFromView($view, $path)
62
    {
63 1
        $this->generateFilePaths();
64
65 1
        $this->generatePdf($this->viewToString($view));
66
67 1
        rename($this->pdfPath, $path);
68 1
    }
69
70
    /**
71
     * Generate paths for the temporary files
72
     * @throws Exception
73
     */
74 1
    protected function generateFilePaths()
75
    {
76 1
        $this->validateStoragePath();
77
78 1
        $path = $this->storagePath . DIRECTORY_SEPARATOR;
79
80 1
        $this->htmlPath = $path . uniqid('pdf-', true).'.html';
81
82 1
        $this->pdfPath = $path . uniqid('html-', true) . '.pdf';
83 1
    }
84
85
    /**
86
     * Validate that the storage path is set and is writable
87
     * @throws \Exception
88
     */
89 3
    protected function validateStoragePath()
90
    {
91 3
        if (is_null($this->storagePath)) {
92 1
            throw new Exception('A storage path has not been set');
93
        }
94
95 2
        if (! is_dir($this->storagePath) || ! is_writable($this->storagePath)) {
96 1
            throw new Exception('The specified storage path is not writable');
97
        }
98 1
    }
99
100
    /**
101
     * Run the script with PhantomJS
102
     * @param string $view
103
     */
104 2
    protected function generatePdf($view)
105
    {
106 2
        $this->saveHtml($view);
107
108 2
        $command = implode(' ', [
109 2
            $this->binaryPath,
110 2
            implode(' ', $this->commandLineOptions),
111 2
            $this->convertScript,
112 2
            $this->prefixHtmlPath($this->htmlPath),
113 2
            $this->pdfPath,
114 2
            $this->orientation
115
        ]);
116
117 2
        $process = new Process($command, __DIR__);
118 2
        $process->setTimeout($this->timeout);
119 2
        $process->run();
120
121 2
        if ($errorOutput = $process->getErrorOutput()) {
122 1
            throw new RuntimeException('PhantomJS: ' . $errorOutput);
123
        }
124
125
        // Remove temporary html file
126 1
        if (is_file($this->htmlPath)) {
127 1
            unlink($this->htmlPath);
128
        }
129 1
    }
130
131
    /**
132
     * Convert the provided view to a string. The __toString method is called manually to be able to catch exceptions
133
     * in the view which is not possible otherwise. https://bugs.php.net/bug.php?id=53648
134
     * @param mixed $view
135
     * @return string
136
     */
137 1
    protected function viewToString($view)
138
    {
139 1
        return is_object($view) ? $view->__toString() : $view;
140
    }
141
142
    /**
143
     * Save a string to a html file
144
     * @param string $html
145
     */
146 1
    protected function saveHtml($html)
147
    {
148 1
        $html = $this->insertBaseTag($html);
149
150 1
        file_put_contents($this->htmlPath, $html);
151 1
    }
152
153
    /**
154
     * Insert a base tag after the head tag to allow relative references to assets
155
     * @param string $view
156
     * @return string
157
     */
158 2
    protected function insertBaseTag($view)
159
    {
160 2
        if (is_null($this->baseUrl)) {
161 1
            return $view;
162
        }
163
164 1
        return str_replace('<head>', '<head><base href="'.$this->baseUrl.'">', $view);
165
    }
166
167
    /**
168
     * Prefix the input path for windows versions of PhantomJS
169
     * @param string $path
170
     * @return string
171
     */
172 1
    public function prefixHtmlPath($path)
173
    {
174 1
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
175
            return 'file:///' . $path;
176
        }
177
178 1
        return $path;
179
    }
180
181
    /**
182
     * Set the base url for the base tag
183
     * @param string $url
184
     * @return self
185
     */
186 1
    public function setBaseUrl($url)
187
    {
188 1
        $this->baseUrl = $url;
189
190 1
        return $this;
191
    }
192
193 1
    public function getBaseUrl()
194
    {
195 1
        return $this->baseUrl;
196
    }
197
198
    /**
199
     * Set the binary path
200
     * @param string $path
201
     * @return self
202
     */
203 1
    public function setBinaryPath($path)
204
    {
205 1
        $this->binaryPath = $path;
206
207 1
        return $this;
208
    }
209
210 1
    public function getBinaryPath()
211
    {
212 1
        return $this->binaryPath;
213
    }
214
215
    /**
216
     * Set the storage path for temporary files
217
     * @param string $path
218
     * @return self
219
     */
220 1
    public function setStoragePath($path)
221
    {
222 1
        $this->storagePath = $path;
223
224 1
        return $this;
225
    }
226
227 1
    public function getStoragePath()
228
    {
229 1
        return $this->storagePath;
230
    }
231
232
    /**
233
     * @param  int $seconds
234
     * @return self
235
     */
236 1
    public function setTimeout($seconds)
237
    {
238 1
        $this->timeout = (int) $seconds;
239
240 1
        return $this;
241
    }
242
243
    /**
244
     * @return int
245
     */
246 1
    public function getTimeout()
247
    {
248 1
        return $this->timeout;
249
    }
250
251
    /**
252
     * Ignore PhantomJS SSL errors
253
     * @return self
254
     */
255 1
    public function ignoreSSLErrors()
256
    {
257 1
        $this->commandLineOptions[] = '--ignore-ssl-errors=true';
258
259 1
        return $this;
260
    }
261
262
    /**
263
     * Add a command line option for PhantomJS
264
     * @param string $option
265
     * @return self
266
     */
267 1
    public function addCommandLineOption($option)
268
    {
269 1
        $this->commandLineOptions[] = $option;
270
271 1
        return $this;
272
    }
273
274
    /**
275
     * @return array
276
     */
277 1
    public function getCommandLineOptions()
278
    {
279 1
        return $this->commandLineOptions;
280
    }
281
282
    /**
283
     * Use a custom script to be run via PhantomJS
284
     * @param string $path
285
     * @return self
286
     */
287 1
    public function setConvertScript($path)
288
    {
289 1
        $this->convertScript = $path;
290
291 1
        return $this;
292
    }
293
294
    /**
295
     * @return string
296
     */
297 1
    public function getConvertScript()
298
    {
299 1
        return $this->convertScript;
300
    }
301
302
    /**
303
     * @return string
304
     */
305
    public function getOrientation()
306
    {
307
        return $this->orientation;
308
    }
309
310
    /**
311
     * @param string $orientation
312
     * @return self
313
     */
314
    public function setOrientation($orientation)
315
    {
316
        $this->orientation = $orientation;
317
318
        return $this;
319
    }
320
}
321