Completed
Push — master ( 0002c8...bd98b1 )
by Mathieu
05:01 queued 01:49
created

PDF::output()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
crap 2
1
<?php
2
3
namespace MathieuTu\PDFLayer;
4
5
use GuzzleHttp\Client;
6
use Illuminate\Contracts\Config\Repository as ConfigRepository;
7
use Illuminate\Contracts\View\Factory as ViewFactory;
8
use Illuminate\Filesystem\Filesystem;
9
use Illuminate\Http\Response;
10
use Illuminate\Support\Str;
11
use MathieuTu\PDFLayer\Exceptions\PDFLayerException;
12
13
class PDF
14
{
15
    private $httpClient;
16
    private $view;
17
    private $files;
18
    private $config;
19
    private $params;
20
    private $pdf;
21
22 13
    public function __construct(Client $httpClient, ConfigRepository $config, Filesystem $files, ViewFactory $view)
23
    {
24 13
        $this->httpClient = $httpClient;
25 13
        $this->view = $view;
26 13
        $this->files = $files;
27 13
        $this->config = $this->prepareConfig($config);
28 13
        $this->params = $this->prepareParams();
29 13
    }
30
31
    /**
32
     * @param \Illuminate\Contracts\Config\Repository $config
33
     *
34
     * @return array
35
     */
36 13
    private function prepareConfig(ConfigRepository $config)
37
    {
38 13
        return $config->get('pdflayer');
39
    }
40
41
    /**
42
     * @return \Illuminate\Support\Collection
43
     */
44 13
    private function prepareParams()
45
    {
46 13
        $params = collect($this->config['default_params']);
47 13
        if ($this->config['sandbox']) {
48 13
            $params['test'] = 1;
49 13
        }
50
51 13
        return $params;
52
    }
53
54
    /**
55
     * Load HTML and encoding from an URL.
56
     *
57
     * @param $url
58
     *
59
     * @return $this
60
     */
61 1
    public function loadUrl($url)
62
    {
63 1
        $this->params['document_url'] = urlencode($url);
64
65 1
        if (!empty($this->config['secret_keyword'])) {
66 1
            $this->params['secret_key'] = md5($url . $this->config['secret_keyword']);
67 1
        }
68
69 1
        return $this;
70
    }
71
72
    /**
73
     * Load a View and convert it to HTML.
74
     *
75
     * @param string $view
76
     * @param array  $data
77
     * @param array  $mergeData
78
     * @param string $encoding
79
     *
80
     * @return $this
81
     */
82 1
    public function loadView($view, $data = [], $mergeData = [], $encoding = null)
83
    {
84 1
        $html = $this->view->make($view, $data, $mergeData)->render();
85
86 1
        return $this->loadHTML($html, $encoding);
87
    }
88
89
    /**
90
     * Load a HTML string.
91
     *
92
     * @param string $html
93
     * @param string $encoding
94
     *
95
     * @return $this
96
     */
97 3
    public function loadHTML($html, $encoding = null)
98
    {
99 3
        $this->params['document_html'] = $html;
100
101 3
        if ($encoding) {
1 ignored issue
show
Bug Best Practice introduced by
The expression $encoding of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
102 2
            $this->params['text_encoding'] = $encoding;
103 2
        }
104
105 3
        return $this;
106
    }
107
108
    /**
109
     * Load a HTML file.
110
     *
111
     * @param string $file
112
     */
113 1
    public function loadFile($file)
114
    {
115 1
        $html = file_get_contents($file);
116 1
        $encoding = null;
117 1
        if (isset($http_response_header)) {
118 1
            foreach ($http_response_header as $_header) {
119 1
                if (preg_match("@Content-Type:\s*[\w/]+;\s*?charset=([\S]+)@i", $_header, $matches)) {
120 1
                    $encoding = strtoupper($matches[1]);
121 1
                    break;
122
                }
123 1
            }
124 1
        }
125 1
        $this->loadHTML($html, $encoding);
126 1
    }
127
128
    /**
129
     * Set the paper size and orientation.
130
     *
131
     * @param string $layout
132
     * @param string $orientation
133
     *
134
     * @return $this
135
     */
136 1
    public function setPaper($layout, $orientation = 'portrait')
137
    {
138 1
        $this->params['page_size'] = $layout;
139 1
        $this->params['orientation'] = $orientation;
140
141 1
        return $this;
142
    }
143
144
    /**
145
     * Return a response with the PDF to show in the browser.
146
     *
147
     * @param string $filename
148
     *
149
     * @throws \InvalidArgumentException
150
     *
151
     * @return \Illuminate\Http\Response
152
     */
153 1 View Code Duplication
    public function stream($filename = 'document.pdf')
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
154
    {
155 1
        $output = $this->output();
156
157 1
        return new Response($output, 200, [
158 1
            'Content-Type'        => 'application/pdf',
159 1
            'Content-Disposition' => 'inline; filename="' . $filename . '"',
160 1
        ]);
161
    }
162
163
    /**
164
     * Output the PDF as a string.
165
     *
166
     * @throws \Exception
167
     *
168
     * @return string The rendered PDF as string
169
     */
170 4
    public function output()
171
    {
172 4
        if (!$this->pdf) {
173 4
            $this->render();
174 4
        }
175
176 4
        return $this->pdf;
177
    }
178
179
    /**
180
     * @throws \Exception
181
     */
182 4
    private function render()
183
    {
184 4
        list($uri, $postParams) = $this->prepareRequest();
185 4
        $this->pdf = $this->doRequest($uri, $postParams);
186 4
    }
187
188
    /**
189
     * @return array
190
     */
191 12
    private function prepareRequest()
192
    {
193 12
        $uri = $this->config['endpoint'] . '?access_key=' . $this->config['access_key'];
194
195 12
        $postKeys = ['document_html', 'header_html'];
196 12
        $getParams = $this->params->except($postKeys)->toArray();
197
198 12
        $uri .= '&' . http_build_query($getParams);
199 12
        $postParams = $this->params->diff($getParams)->toArray();
200
201 12
        return [$uri, $postParams];
202
    }
203
204
    /**
205
     * @param $uri
206
     * @param $postParams
207
     *
208
     * @throws \RuntimeException
209
     * @throws \MathieuTu\PDFLayer\Exceptions\PDFLayerException
210
     *
211
     * @return string
212
     */
213 4
    private function doRequest($uri, $postParams)
214
    {
215 4
        $response = $this->httpClient->post($uri, [
216 4
            'form_params' => $postParams,
217 4
        ]);
218
219 4
        $content = $response->getBody()->getContents();
220
221 4
        $error = json_decode($content);
222 4
        if (is_object($error)) {
223 1
            throw new PDFLayerException($error);
224
        }
225
226 4
        return $content;
227
    }
228
229
    /**
230
     * Make the PDF downloadable by the user.
231
     *
232
     * @param string $filename
233
     *
234
     * @throws \InvalidArgumentException
235
     * @throws \Exception
236
     *
237
     * @return \Illuminate\Http\Response
238
     */
239 1 View Code Duplication
    public function download($filename = 'document.pdf')
1 ignored issue
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
240
    {
241 1
        $output = $this->output();
242
243 1
        return new Response($output, 200, [
244 1
            'Content-Type'        => 'application/pdf',
245 1
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
246 1
        ]);
247
    }
248
249
    /**
250
     * Save the PDF to a file.
251
     *
252
     * @param $filename
253
     *
254
     * @return $this
255
     */
256 1
    public function save($filename)
257
    {
258 1
        $this->files->put($filename, $this->output());
259
260 1
        return $this;
261
    }
262
263
    /**
264
     * @param $name
265
     * @param $arguments
266
     *
267
     * @throws \InvalidArgumentException
268
     * @throws \BadMethodCallException
269
     *
270
     * @return $this
271
     */
272 1
    public function __call($name, $arguments)
273
    {
274 1
        if (Str::startsWith($name, 'set')) {
275 1
            $propertyCamel = Str::substr($name, Str::length('set'));
276 1
            $property = Str::snake($propertyCamel);
277
278 1
            $this->params[$property] = $arguments[0];
279
280 1
            return $this;
281
        }
282
283
        throw new \BadMethodCallException('Call to undefined method ' . static::class . '::' . $name . '()');
284
    }
285
286
    /**
287
     * @param $name
288
     * @param $value
289
     *
290
     * @return mixed
291
     */
292 1
    public function __set($name, $value)
293
    {
294 1
        return $this->params[$name] = $value;
295
    }
296
297
    /**
298
     * Add some parameters.
299
     *
300
     * @param array $params
301
     *
302
     * @return $this
303
     */
304 1
    public function addParams(array $params)
305
    {
306 1
        return $this->setParams($params);
307
    }
308
309
    /**
310
     * Add/Replace some parameters.
311
     *
312
     * @param array $params
313
     * @param bool  $replace
314
     *
315
     * @return $this
316
     */
317 2
    public function setParams(array $params, $replace = false)
318
    {
319 2
        if ($replace) {
320 1
            $this->params = collect($params);
321 1
        } else {
322 2
            $this->params = $this->params->merge($params);
1 ignored issue
show
Bug introduced by
The method merge cannot be called on $this->params (of type array<string,string>).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
323
        }
324
325 2
        return $this;
326
    }
327
328
    /**
329
     * Replace some parameters.
330
     *
331
     * @param array $params
332
     *
333
     * @return $this
334
     */
335 1
    public function replaceParams(array $params)
336
    {
337 1
        return $this->setParams($params, true);
338
    }
339
340
    /**
341
     * See all the current parameters.
342
     *
343
     * @return array
344
     */
345
    public function seeParams()
346
    {
347
        return $this->params->toArray();
348
    }
349
350
    /**
351
     * See the arguments which will be sent during the request.
352
     *
353
     * @param string $key
354
     *
355
     * @return array
356
     */
357 8
    public function seeRequestArgs($key = null)
358
    {
359 8
        list($uri, $postParams) = $this->prepareRequest();
360
361 8
        if ($key) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $key of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
362
            return ${$key};
363
        }
364
365 8
        return compact('uri', 'postParams');
366
    }
367
}
368