Failed Conditions
Push — master ( 07c60b...7328e1 )
by Adrien
12:29
created

Sample::displayGrid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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