Test Failed
Branch master (453945)
by Florian
02:31
created

WkhtmlToPdfRenderer   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Test Coverage

Coverage 75.34%

Importance

Changes 0
Metric Value
wmc 23
eloc 76
dl 0
loc 176
ccs 55
cts 73
cp 0.7534
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setBinary() 0 13 3
A render() 0 19 3
F buildCommand() 0 60 14
A __construct() 0 8 2
A exec() 0 17 1
1
<?php
2
declare(strict_types = 1);
3
4
namespace Phauthentic\Presentation\Renderer;
5
6
use InvalidArgumentException;
7
use Phauthentic\Presentation\View\PdfViewInterface;
8
use Phauthentic\Presentation\View\ViewInterface;
9
use RuntimeException;
10
11
/**
12
 * Twig Renderer
13
 */
14
class WkhtmlToPdfRenderer
15
{
16
    /**
17
     * Binary
18
     *
19
     * @var string
20
     */
21
    protected $binary = '/usr/bin/wkhtmltopdf';
22
23
    /**
24
     * Is it running on windows
25
     *
26
     * @var bool
27
     */
28
    protected $isWindowsEnvironment = false;
29
30
    /**
31
     * Cwd for phps proc_open fourth argument
32
     *
33
     * @var string|null
34
     */
35
    protected $cwd = null;
36
37
    /**
38
     * Sets the path for the wkhtmltopdf binary
39
     *
40
     * @return $this
41
     */
42
    public function setBinary(string $binary): self
43
    {
44
        if (!file_exists($binary)) {
45
            throw new InvalidArgumentException(sprintf('Binary %s does not exist', $binary));
46
        }
47
48
        if (!is_executable($binary)) {
49
            throw new RuntimeException(sprintf('%s not a binary or can not be executed', $binary));
50
        }
51
52
        $this->binary = $binary;
53
54
        return $this;
55
    }
56
57
    /**
58
     * Constructor
59
     */
60 1
    public function __construct(array $options = [])
61
    {
62 1
        $this->options = $options;
0 ignored issues
show
Bug Best Practice introduced by
The property options does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
63 1
        $this->cwd = sys_get_temp_dir();
64 1
        $this->isWindowsEnvironment = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
65
66 1
        if ($this->isWindowsEnvironment) {
67
            $this->setBinary('C:/Progra~1/wkhtmltopdf/bin/wkhtmltopdf.exe');
68
        }
69 1
    }
70
71
    /**
72
     * Generates Pdf from html
73
     *
74
     * @return string Raw PDF data
75
     * @throws \Exception If no output is generated to stdout by wkhtmltopdf.
76
     */
77 1
    public function render(PdfViewInterface $view): string
78
    {
79 1
        $command = $this->buildCommand($view);
80 1
        $content = $this->exec($command, $view->getHtml());
0 ignored issues
show
Bug introduced by
The method getHtml() does not exist on Phauthentic\Presentation\View\PdfViewInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface. ( Ignorable by Annotation )

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

80
        $content = $this->exec($command, $view->/** @scrutinizer ignore-call */ getHtml());
Loading history...
81
82 1
        if (!empty($content['stdout'])) {
83 1
            return $content['stdout'];
84
        }
85
86
        if (!empty($content['stderr'])) {
87
            throw new RuntimeException(sprintf(
88
                'System error "%s" when executing command "%s". ' .
89
                'Try using the binary provided on http://wkhtmltopdf.org/downloads.html',
90
                $content['stderr'],
91
                $command
92
            ));
93
        }
94
95
        throw new RuntimeException("WKHTMLTOPDF didn't return any data");
96
    }
97
98
    /**
99
     * Execute the WkHtmlToPdf commands for rendering pdfs
100
     *
101
     * @param string $cmd the command to execute
102
     * @param string $input Html to pass to wkhtmltopdf
103
     * @return array the result of running the command to generate the pdf
104
     */
105 1
    protected function exec($cmd, $input)
106
    {
107 1
        $result = ['stdout' => '', 'stderr' => '', 'return' => ''];
108
109 1
        $proc = proc_open($cmd, [0 => ['pipe', 'r'], 1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes, $this->cwd);
110 1
        fwrite($pipes[0], $input);
111 1
        fclose($pipes[0]);
112
113 1
        $result['stdout'] = stream_get_contents($pipes[1]);
114 1
        fclose($pipes[1]);
115
116 1
        $result['stderr'] = stream_get_contents($pipes[2]);
117 1
        fclose($pipes[2]);
118
119 1
        $result['return'] = proc_close($proc);
0 ignored issues
show
Bug introduced by
It seems like $proc can also be of type false; however, parameter $process of proc_close() 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

119
        $result['return'] = proc_close(/** @scrutinizer ignore-type */ $proc);
Loading history...
120
121 1
        return $result;
122
    }
123
124
    /**
125
     * Get the command to render a pdf
126
     *
127
     *
128
     * @return string the command for generating the pdf
129
     */
130 1
    protected function buildCommand(PdfViewInterface $pdfView): string
131
    {
132
        $options = [
133 1
            'quiet' => true,
134
            'print-media-type' => true,
135 1
            'orientation' => $pdfView->getOrientation(),
136 1
            'page-size' => $pdfView->getPageSize(),
137 1
            'encoding' => $pdfView->getEncoding(),
138 1
            'title' => $pdfView->getTitle(),
0 ignored issues
show
Bug introduced by
The method getTitle() does not exist on Phauthentic\Presentation\View\PdfViewInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface. ( Ignorable by Annotation )

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

138
            'title' => $pdfView->/** @scrutinizer ignore-call */ getTitle(),
Loading history...
139 1
            'javascript-delay' => $pdfView->getJsDelay(),
0 ignored issues
show
Bug introduced by
The method getJsDelay() does not exist on Phauthentic\Presentation\View\PdfViewInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface. ( Ignorable by Annotation )

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

139
            'javascript-delay' => $pdfView->/** @scrutinizer ignore-call */ getJsDelay(),
Loading history...
140 1
            'window-status' => $pdfView->getWindowStatus(),
0 ignored issues
show
Bug introduced by
The method getWindowStatus() does not exist on Phauthentic\Presentation\View\PdfViewInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface. ( Ignorable by Annotation )

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

140
            'window-status' => $pdfView->/** @scrutinizer ignore-call */ getWindowStatus(),
Loading history...
141
        ];
142
143 1
        $margin = $pdfView->getMargin();
0 ignored issues
show
Bug introduced by
The method getMargin() does not exist on Phauthentic\Presentation\View\PdfViewInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface. ( Ignorable by Annotation )

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

143
        /** @scrutinizer ignore-call */ 
144
        $margin = $pdfView->getMargin();
Loading history...
144 1
        foreach ($margin as $key => $value) {
145 1
            if ($value !== null) {
146 1
                $options['margin-' . $key] = $value . 'mm';
147
            }
148
        }
149 1
        $options = array_merge($options, (array)$this->options);
150
151 1
        if ($this->isWindowsEnvironment) {
152
            $command = '"' . $this->binary . '"';
153
        } else {
154 1
            $command = $this->binary;
155
        }
156
157 1
        foreach ($options as $key => $value) {
158 1
            if (empty($value)) {
159 1
                continue;
160 1
            } elseif (is_array($value)) {
161
                foreach ($value as $k => $v) {
162
                    $command .= sprintf(' --%s %s %s', $key, escapeshellarg($k), escapeshellarg($v));
163
                }
164 1
            } elseif ($value === true) {
165 1
                $command .= ' --' . $key;
166
            } else {
167 1
                $command .= sprintf(' --%s %s', $key, escapeshellarg($value));
168
            }
169
        }
170 1
        $footer = $pdfView->footer();
0 ignored issues
show
Bug introduced by
The method footer() does not exist on Phauthentic\Presentation\View\PdfViewInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface. ( Ignorable by Annotation )

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

170
        /** @scrutinizer ignore-call */ 
171
        $footer = $pdfView->footer();
Loading history...
171 1
        foreach ($footer as $location => $text) {
172 1
            if ($text !== null) {
173 1
                $command .= " --footer-$location \"" . addslashes($text) . "\"";
174
            }
175
        }
176
177 1
        $header = $pdfView->header();
0 ignored issues
show
Bug introduced by
The method header() does not exist on Phauthentic\Presentation\View\PdfViewInterface. Since it exists in all sub-types, consider adding an abstract or default implementation to Phauthentic\Presentation\View\PdfViewInterface. ( Ignorable by Annotation )

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

177
        /** @scrutinizer ignore-call */ 
178
        $header = $pdfView->header();
Loading history...
178 1
        foreach ($header as $location => $text) {
179 1
            if ($text !== null) {
180 1
                $command .= " --header-$location \"" . addslashes($text) . "\"";
181
            }
182
        }
183 1
        $command .= " - -";
184
185 1
        if ($this->isWindowsEnvironment) {
186
            $command = '"' . $command . '"';
187
        }
188
189 1
        return $command;
190
    }
191
}
192