Completed
Push — master ( ec0e45...440039 )
by Mark
41s queued 37s
created

Sample::renderChart()   A

Complexity

Conditions 4
Paths 7

Size

Total Lines 19
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 12
c 2
b 0
f 0
dl 0
loc 19
ccs 7
cts 8
cp 0.875
rs 9.8666
cc 4
nc 7
nop 2
crap 4.0312
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Helper;
4
5
use PhpOffice\PhpSpreadsheet\Chart\Chart;
6
use PhpOffice\PhpSpreadsheet\IOFactory;
7
use PhpOffice\PhpSpreadsheet\Settings;
8
use PhpOffice\PhpSpreadsheet\Spreadsheet;
9
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
10
use PhpOffice\PhpSpreadsheet\Writer\IWriter;
11
use RecursiveDirectoryIterator;
12
use RecursiveIteratorIterator;
13
use RecursiveRegexIterator;
14
use ReflectionClass;
15
use RegexIterator;
16
use RuntimeException;
17
use Throwable;
18
19
/**
20
 * Helper class to be used in sample code.
21
 */
22
class Sample
23
{
24
    /**
25
     * Returns whether we run on CLI or browser.
26 277
     *
27
     * @return bool
28 277
     */
29
    public function isCli()
30
    {
31
        return PHP_SAPI === 'cli';
32
    }
33
34
    /**
35
     * Return the filename currently being executed.
36 1
     *
37
     * @return string
38 1
     */
39
    public function getScriptFilename()
40
    {
41
        return basename($_SERVER['SCRIPT_FILENAME'], '.php');
42
    }
43
44
    /**
45
     * Whether we are executing the index page.
46 1
     *
47
     * @return bool
48 1
     */
49
    public function isIndex()
50
    {
51
        return $this->getScriptFilename() === 'index';
52
    }
53
54
    /**
55
     * Return the page title.
56 1
     *
57
     * @return string
58 1
     */
59
    public function getPageTitle()
60
    {
61
        return $this->isIndex() ? 'PHPSpreadsheet' : $this->getScriptFilename();
62
    }
63
64
    /**
65
     * Return the page heading.
66 1
     *
67
     * @return string
68 1
     */
69
    public function getPageHeading()
70
    {
71
        return $this->isIndex() ? '' : '<h1>' . str_replace('_', ' ', $this->getScriptFilename()) . '</h1>';
72
    }
73
74
    /**
75
     * Returns an array of all known samples.
76 1
     *
77
     * @return string[][] [$name => $path]
78
     */
79 1
    public function getSamples()
80 1
    {
81
        // Populate samples
82
        $baseDir = realpath(__DIR__ . '/../../../samples');
83
        if ($baseDir === false) {
84
            // @codeCoverageIgnoreStart
85 1
            throw new RuntimeException('realpath returned false');
86 1
            // @codeCoverageIgnoreEnd
87 1
        }
88
        $directory = new RecursiveDirectoryIterator($baseDir);
89 1
        $iterator = new RecursiveIteratorIterator($directory);
90 1
        $regex = new RegexIterator($iterator, '/^.+\.php$/', RecursiveRegexIterator::GET_MATCH);
91 1
92 1
        $files = [];
93
        foreach ($regex as $file) {
94
            $file = str_replace(str_replace('\\', '/', $baseDir) . '/', '', str_replace('\\', '/', $file[0]));
95
            if (is_array($file)) {
96
                // @codeCoverageIgnoreStart
97 1
                throw new RuntimeException('str_replace returned array');
98 1
                // @codeCoverageIgnoreEnd
99 1
            }
100 1
            $info = pathinfo($file);
101 1
            $category = str_replace('_', ' ', $info['dirname'] ?? '');
102 1
            $name = str_replace('_', ' ', (string) preg_replace('/(|\.php)/', '', $info['filename']));
103
            if (!in_array($category, ['.', 'boostrap', 'templates'])) {
104 1
                if (!isset($files[$category])) {
105
                    $files[$category] = [];
106
                }
107
                $files[$category][$name] = $file;
108
            }
109 1
        }
110 1
111 1
        // Sort everything
112
        ksort($files);
113
        foreach ($files as &$f) {
114 1
            asort($f);
115
        }
116
117
        return $files;
118
    }
119
120
    /**
121
     * Write documents.
122
     *
123 75
     * @param string $filename
124
     * @param string[] $writers
125
     */
126 75
    public function write(Spreadsheet $spreadsheet, $filename, array $writers = ['Xlsx', 'Xls'], bool $withCharts = false): void
127
    {
128
        // Set active sheet index to the first sheet, so Excel opens this as the first sheet
129 75
        $spreadsheet->setActiveSheetIndex(0);
130 75
131 75
        // Write documents
132 75
        foreach ($writers as $writerType) {
133 75
            $path = $this->getFilename($filename, mb_strtolower($writerType));
134 75
            $writer = IOFactory::createWriter($spreadsheet, $writerType);
135 75
            if ($writerType === 'Xlsx' && $withCharts === true) {
136
                $writer->setIncludeCharts(true);
137
            }
138
            $callStartTime = microtime(true);
139
            $writer->save($path);
140 75
            $this->logWrite($writer, $path, /** @scrutinizer ignore-type */ $callStartTime);
141
            if ($this->isCli() === false) {
142
                echo '<a href="/download.php?type=' . pathinfo($path, PATHINFO_EXTENSION) . '&name=' . basename($path) . '">Download ' . basename($path) . '</a><br />';
1 ignored issue
show
Bug introduced by
Are you sure pathinfo($path, PhpOffic...per\PATHINFO_EXTENSION) of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

142
                echo '<a href="/download.php?type=' . /** @scrutinizer ignore-type */ pathinfo($path, PATHINFO_EXTENSION) . '&name=' . basename($path) . '">Download ' . basename($path) . '</a><br />';
Loading history...
143 116
            }
144
        }
145 116
146
        $this->logEndingNotes();
147
    }
148
149
    protected function isDirOrMkdir(string $folder): bool
150
    {
151
        return \is_dir($folder) || \mkdir($folder);
152
    }
153 117
154
    /**
155 117
     * Returns the temporary directory and make sure it exists.
156 117
     *
157 1
     * @return string
158
     */
159
    public function getTemporaryFolder()
160 116
    {
161
        $tempFolder = sys_get_temp_dir() . '/phpspreadsheet';
162
        if (!$this->isDirOrMkdir($tempFolder)) {
163
            throw new RuntimeException(sprintf('Directory "%s" was not created', $tempFolder));
164
        }
165
166
        return $tempFolder;
167
    }
168
169
    /**
170
     * Returns the filename that should be used for sample output.
171 115
     *
172
     * @param string $filename
173 115
     * @param string $extension
174
     */
175 115
    public function getFilename($filename, $extension = 'xlsx'): string
176
    {
177
        $originalExtension = pathinfo($filename, PATHINFO_EXTENSION);
178
179
        return $this->getTemporaryFolder() . '/' . str_replace('.' . /** @scrutinizer ignore-type */ $originalExtension, '.' . $extension, basename($filename));
180
    }
181
182
    /**
183
     * Return a random temporary file name.
184
     *
185 7
     * @param string $extension
186
     *
187 7
     * @return string
188 7
     */
189
    public function getTemporaryFilename($extension = 'xlsx')
190
    {
191
        $temporaryFilename = tempnam($this->getTemporaryFolder(), 'phpspreadsheet-');
192
        if ($temporaryFilename === false) {
193 7
            // @codeCoverageIgnoreStart
194
            throw new RuntimeException('tempnam returned false');
195 7
            // @codeCoverageIgnoreEnd
196
        }
197
        unlink($temporaryFilename);
198 277
199
        return $temporaryFilename . '.' . $extension;
200 277
    }
201 277
202
    public function log(string $message): void
203
    {
204 87
        $eol = $this->isCli() ? PHP_EOL : '<br />';
205
        echo($this->isCli() ? date('H:i:s ') : '') . $message . $eol;
206 87
    }
207 87
208
    public function renderChart(Chart $chart, string $fileName): void
209 87
    {
210
        if ($this->isCli() === true) {
211
            return;
212 23
        }
213
214 23
        Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\MtJpGraphRenderer::class);
215 23
216
        $fileName = $this->getFilename($fileName, 'png');
217
218 12
        try {
219
            $chart->render($fileName);
220
            $this->log('Rendered image: ' . $fileName);
221
            $imageData = file_get_contents($fileName);
222
            if ($imageData !== false) {
223
                echo '<div><img src="data:image/gif;base64,' . base64_encode($imageData) . '" /></div>';
224 12
            }
225 12
        } catch (Throwable $e) {
226
            $this->log('Error rendering chart: ' . $e->getMessage() . PHP_EOL);
227 12
        }
228 12
    }
229
230
    public function titles(string $category, string $functionName, ?string $description = null): void
231
    {
232
        $this->log(sprintf('%s Functions:', $category));
233
        $description === null
234 78
            ? $this->log(sprintf('Function: %s()', rtrim($functionName, '()')))
235
            : $this->log(sprintf('Function: %s() - %s.', rtrim($functionName, '()'), rtrim($description, '.')));
236
    }
237 78
238
    public function displayGrid(array $matrix): void
239
    {
240
        $renderer = new TextGrid($matrix, $this->isCli());
241
        echo $renderer->render();
242
    }
243
244
    public function logCalculationResult(
245
        Worksheet $worksheet,
246 110
        string $functionName,
247
        string $formulaCell,
248 110
        ?string $descriptionCell = null
249 110
    ): void {
250 110
        if ($descriptionCell !== null) {
251 110
            $this->log($worksheet->getCell($descriptionCell)->getValue());
252
        }
253 110
        $this->log($worksheet->getCell($formulaCell)->getValue());
254 110
        $this->log(sprintf('%s() Result is ', $functionName) . $worksheet->getCell($formulaCell)->getCalculatedValue());
255
    }
256
257 110
    /**
258
     * Log ending notes.
259
     */
260
    public function logEndingNotes(): void
261
    {
262
        // Do not show execution time for index
263
        $this->log('Peak memory usage: ' . (memory_get_peak_usage(true) / 1024 / 1024) . 'MB');
264
    }
265
266
    /**
267 14
     * Log a line about the write operation.
268
     *
269 14
     * @param string $path
270 14
     * @param float $callStartTime
271 14
     */
272
    public function logWrite(IWriter $writer, $path, $callStartTime): void
273 14
    {
274
        $callEndTime = microtime(true);
275
        $callTime = $callEndTime - $callStartTime;
276
        $reflection = new ReflectionClass($writer);
277
        $format = $reflection->getShortName();
278
279
        $message = ($this->isCli() === true)
280
            ? "Write {$format} format to {$path}  in " . sprintf('%.4f', $callTime) . ' seconds'
281
            : "Write {$format} format to <code>{$path}</code>  in " . sprintf('%.4f', $callTime) . ' seconds';
282
283
        $this->log($message);
284
    }
285
286
    /**
287
     * Log a line about the read operation.
288
     *
289
     * @param string $format
290
     * @param string $path
291
     * @param float $callStartTime
292
     */
293
    public function logRead($format, $path, $callStartTime): void
294
    {
295
        $callEndTime = microtime(true);
296
        $callTime = $callEndTime - $callStartTime;
297
        $message = "Read {$format} format from <code>{$path}</code>  in " . sprintf('%.4f', $callTime) . ' seconds';
298
299
        $this->log($message);
300
    }
301
}
302