Passed
Push — master ( 440039...6cc2bb )
by Mark
23:06 queued 12:16
created

Sample::getScriptFilename()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
ccs 2
cts 2
cp 1
crap 1
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
     *
27
     * @return bool
28
     */
29 277
    public function isCli()
30
    {
31 277
        return PHP_SAPI === 'cli';
32
    }
33
34
    /**
35
     * Return the filename currently being executed.
36
     *
37
     * @return string
38
     */
39 1
    public function getScriptFilename()
40
    {
41 1
        return basename($_SERVER['SCRIPT_FILENAME'], '.php');
42
    }
43
44
    /**
45
     * Whether we are executing the index page.
46
     *
47
     * @return bool
48
     */
49 1
    public function isIndex()
50
    {
51 1
        return $this->getScriptFilename() === 'index';
52
    }
53
54
    /**
55
     * Return the page title.
56
     *
57
     * @return string
58
     */
59 1
    public function getPageTitle()
60
    {
61 1
        return $this->isIndex() ? 'PHPSpreadsheet' : $this->getScriptFilename();
62
    }
63
64
    /**
65
     * Return the page heading.
66
     *
67
     * @return string
68
     */
69 1
    public function getPageHeading()
70
    {
71 1
        return $this->isIndex() ? '' : '<h1>' . str_replace('_', ' ', $this->getScriptFilename()) . '</h1>';
72
    }
73
74
    /**
75
     * Returns an array of all known samples.
76
     *
77
     * @return string[][] [$name => $path]
78
     */
79 1
    public function getSamples()
80
    {
81
        // Populate samples
82 1
        $baseDir = realpath(__DIR__ . '/../../../samples');
83 1
        if ($baseDir === false) {
84
            // @codeCoverageIgnoreStart
85
            throw new RuntimeException('realpath returned false');
86
            // @codeCoverageIgnoreEnd
87
        }
88 1
        $directory = new RecursiveDirectoryIterator($baseDir);
89 1
        $iterator = new RecursiveIteratorIterator($directory);
90 1
        $regex = new RegexIterator($iterator, '/^.+\.php$/', RecursiveRegexIterator::GET_MATCH);
91
92 1
        $files = [];
93 1
        foreach ($regex as $file) {
94 1
            $file = str_replace(str_replace('\\', '/', $baseDir) . '/', '', str_replace('\\', '/', $file[0]));
95 1
            if (is_array($file)) {
96
                // @codeCoverageIgnoreStart
97
                throw new RuntimeException('str_replace returned array');
98
                // @codeCoverageIgnoreEnd
99
            }
100 1
            $info = pathinfo($file);
101 1
            $category = str_replace('_', ' ', $info['dirname'] ?? '');
102 1
            $name = str_replace('_', ' ', (string) preg_replace('/(|\.php)/', '', $info['filename']));
103 1
            if (!in_array($category, ['.', 'boostrap', 'templates'])) {
104 1
                if (!isset($files[$category])) {
105 1
                    $files[$category] = [];
106
                }
107 1
                $files[$category][$name] = $file;
108
            }
109
        }
110
111
        // Sort everything
112 1
        ksort($files);
113 1
        foreach ($files as &$f) {
114 1
            asort($f);
115
        }
116
117 1
        return $files;
118
    }
119
120
    /**
121
     * Write documents.
122
     *
123
     * @param string $filename
124
     * @param string[] $writers
125
     */
126 100
    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 100
        $spreadsheet->setActiveSheetIndex(0);
130
131
        // Write documents
132 100
        foreach ($writers as $writerType) {
133 100
            $path = $this->getFilename($filename, mb_strtolower($writerType));
134 100
            $writer = IOFactory::createWriter($spreadsheet, $writerType);
135 100
            if ($writerType === 'Xlsx' && $withCharts === true) {
136 25
                $writer->setIncludeCharts(true);
137
            }
138 100
            $callStartTime = microtime(true);
139 100
            $writer->save($path);
140 100
            $this->logWrite($writer, $path, /** @scrutinizer ignore-type */ $callStartTime);
141 100
            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
            }
144
        }
145
146 100
        $this->logEndingNotes();
147
    }
148
149 116
    protected function isDirOrMkdir(string $folder): bool
150
    {
151 116
        return \is_dir($folder) || \mkdir($folder);
152
    }
153
154
    /**
155
     * Returns the temporary directory and make sure it exists.
156
     *
157
     * @return string
158
     */
159 117
    public function getTemporaryFolder()
160
    {
161 117
        $tempFolder = sys_get_temp_dir() . '/phpspreadsheet';
162 117
        if (!$this->isDirOrMkdir($tempFolder)) {
163 1
            throw new RuntimeException(sprintf('Directory "%s" was not created', $tempFolder));
164
        }
165
166 116
        return $tempFolder;
167
    }
168
169
    /**
170
     * Returns the filename that should be used for sample output.
171
     *
172
     * @param string $filename
173
     * @param string $extension
174
     */
175 115
    public function getFilename($filename, $extension = 'xlsx'): string
176
    {
177 115
        $originalExtension = pathinfo($filename, PATHINFO_EXTENSION);
178
179 115
        return $this->getTemporaryFolder() . '/' . str_replace('.' . /** @scrutinizer ignore-type */ $originalExtension, '.' . $extension, basename($filename));
180
    }
181
182
    /**
183
     * Return a random temporary file name.
184
     *
185
     * @param string $extension
186
     *
187
     * @return string
188
     */
189 7
    public function getTemporaryFilename($extension = 'xlsx')
190
    {
191 7
        $temporaryFilename = tempnam($this->getTemporaryFolder(), 'phpspreadsheet-');
192 7
        if ($temporaryFilename === false) {
193
            // @codeCoverageIgnoreStart
194
            throw new RuntimeException('tempnam returned false');
195
            // @codeCoverageIgnoreEnd
196
        }
197 7
        unlink($temporaryFilename);
198
199 7
        return $temporaryFilename . '.' . $extension;
200
    }
201
202 277
    public function log(string $message): void
203
    {
204 277
        $eol = $this->isCli() ? PHP_EOL : '<br />';
205 277
        echo($this->isCli() ? date('H:i:s ') : '') . $message . $eol;
206
    }
207
208 26
    public function renderChart(Chart $chart, string $fileName): void
209
    {
210 26
        if ($this->isCli() === true) {
211 26
            return;
212
        }
213
214
        Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\MtJpGraphRenderer::class);
215
216
        $fileName = $this->getFilename($fileName, 'png');
217
218
        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
            }
225
        } catch (Throwable $e) {
226
            $this->log('Error rendering chart: ' . $e->getMessage() . PHP_EOL);
227
        }
228
    }
229
230 87
    public function titles(string $category, string $functionName, ?string $description = null): void
231
    {
232 87
        $this->log(sprintf('%s Functions:', $category));
233 87
        $description === null
234
            ? $this->log(sprintf('Function: %s()', rtrim($functionName, '()')))
235 87
            : $this->log(sprintf('Function: %s() - %s.', rtrim($functionName, '()'), rtrim($description, '.')));
236
    }
237
238 36
    public function displayGrid(array $matrix): void
239
    {
240 36
        $renderer = new TextGrid($matrix, $this->isCli());
241 36
        echo $renderer->render();
242
    }
243
244 12
    public function logCalculationResult(
245
        Worksheet $worksheet,
246
        string $functionName,
247
        string $formulaCell,
248
        ?string $descriptionCell = null
249
    ): void {
250 12
        if ($descriptionCell !== null) {
251 12
            $this->log($worksheet->getCell($descriptionCell)->getValue());
252
        }
253 12
        $this->log($worksheet->getCell($formulaCell)->getValue());
254 12
        $this->log(sprintf('%s() Result is ', $functionName) . $worksheet->getCell($formulaCell)->getCalculatedValue());
255
    }
256
257
    /**
258
     * Log ending notes.
259
     */
260 103
    public function logEndingNotes(): void
261
    {
262
        // Do not show execution time for index
263 103
        $this->log('Peak memory usage: ' . (memory_get_peak_usage(true) / 1024 / 1024) . 'MB');
264
    }
265
266
    /**
267
     * Log a line about the write operation.
268
     *
269
     * @param string $path
270
     * @param float $callStartTime
271
     */
272 110
    public function logWrite(IWriter $writer, $path, $callStartTime): void
273
    {
274 110
        $callEndTime = microtime(true);
275 110
        $callTime = $callEndTime - $callStartTime;
276 110
        $reflection = new ReflectionClass($writer);
277 110
        $format = $reflection->getShortName();
278
279 110
        $message = ($this->isCli() === true)
280 110
            ? "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 110
        $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 14
    public function logRead($format, $path, $callStartTime): void
294
    {
295 14
        $callEndTime = microtime(true);
296 14
        $callTime = $callEndTime - $callStartTime;
297 14
        $message = "Read {$format} format from <code>{$path}</code>  in " . sprintf('%.4f', $callTime) . ' seconds';
298
299 14
        $this->log($message);
300
    }
301
}
302