Passed
Push — master ( 06d9dc...fb3793 )
by Adrien
11:50
created

Worksheet::writePageSetup()   B

Complexity

Conditions 6
Paths 32

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 6.3357

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 20
c 1
b 0
f 0
nc 32
nop 2
dl 0
loc 31
ccs 15
cts 19
cp 0.7895
crap 6.3357
rs 8.9777
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
4
5
use PhpOffice\PhpSpreadsheet\Cell\Cell;
6
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
7
use PhpOffice\PhpSpreadsheet\RichText\RichText;
8
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
9
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
10
use PhpOffice\PhpSpreadsheet\Style\Conditional;
11
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
12
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
13
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView;
14
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet;
15
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
16
17
/**
18
 * @category   PhpSpreadsheet
19
 *
20
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
21
 */
22
class Worksheet extends WriterPart
23
{
24
    /**
25
     * Write worksheet to XML format.
26
     *
27
     * @param PhpspreadsheetWorksheet $pSheet
28
     * @param string[] $pStringTable
29
     * @param bool $includeCharts Flag indicating if we should write charts
30
     *
31
     * @throws WriterException
32
     *
33
     * @return string XML Output
34
     */
35 105
    public function writeWorksheet(PhpspreadsheetWorksheet $pSheet, $pStringTable = null, $includeCharts = false)
36
    {
37
        // Create XML writer
38 105
        $objWriter = null;
39 105
        if ($this->getParentWriter()->getUseDiskCaching()) {
40
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
41
        } else {
42 105
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
43
        }
44
45
        // XML header
46 105
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
47
48
        // Worksheet
49 105
        $objWriter->startElement('worksheet');
50 105
        $objWriter->writeAttribute('xml:space', 'preserve');
51 105
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
52 105
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
53
54 105
        $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
55 105
        $objWriter->writeAttribute('xmlns:x14', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main');
56 105
        $objWriter->writeAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006');
57 105
        $objWriter->writeAttribute('mc:Ignorable', 'x14ac');
58 105
        $objWriter->writeAttribute('xmlns:x14ac', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac');
59
60
        // sheetPr
61 105
        $this->writeSheetPr($objWriter, $pSheet);
62
63
        // Dimension
64 105
        $this->writeDimension($objWriter, $pSheet);
65
66
        // sheetViews
67 105
        $this->writeSheetViews($objWriter, $pSheet);
68
69
        // sheetFormatPr
70 105
        $this->writeSheetFormatPr($objWriter, $pSheet);
71
72
        // cols
73 105
        $this->writeCols($objWriter, $pSheet);
74
75
        // sheetData
76 105
        $this->writeSheetData($objWriter, $pSheet, $pStringTable);
1 ignored issue
show
Bug introduced by
It seems like $pStringTable can also be of type null; however, parameter $pStringTable of PhpOffice\PhpSpreadsheet...sheet::writeSheetData() does only seem to accept array, 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

76
        $this->writeSheetData($objWriter, $pSheet, /** @scrutinizer ignore-type */ $pStringTable);
Loading history...
77
78
        // sheetProtection
79 105
        $this->writeSheetProtection($objWriter, $pSheet);
80
81
        // protectedRanges
82 105
        $this->writeProtectedRanges($objWriter, $pSheet);
83
84
        // autoFilter
85 105
        $this->writeAutoFilter($objWriter, $pSheet);
86
87
        // mergeCells
88 105
        $this->writeMergeCells($objWriter, $pSheet);
89
90
        // conditionalFormatting
91 105
        $this->writeConditionalFormatting($objWriter, $pSheet);
92
93
        // dataValidations
94 105
        $this->writeDataValidations($objWriter, $pSheet);
95
96
        // hyperlinks
97 105
        $this->writeHyperlinks($objWriter, $pSheet);
98
99
        // Print options
100 105
        $this->writePrintOptions($objWriter, $pSheet);
101
102
        // Page margins
103 105
        $this->writePageMargins($objWriter, $pSheet);
104
105
        // Page setup
106 105
        $this->writePageSetup($objWriter, $pSheet);
107
108
        // Header / footer
109 105
        $this->writeHeaderFooter($objWriter, $pSheet);
110
111
        // Breaks
112 105
        $this->writeBreaks($objWriter, $pSheet);
113
114
        // Drawings and/or Charts
115 105
        $this->writeDrawings($objWriter, $pSheet, $includeCharts);
116
117
        // LegacyDrawing
118 105
        $this->writeLegacyDrawing($objWriter, $pSheet);
119
120
        // LegacyDrawingHF
121 105
        $this->writeLegacyDrawingHF($objWriter, $pSheet);
122
123
        // AlternateContent
124 105
        $this->writeAlternateContent($objWriter, $pSheet);
125
126 105
        $objWriter->endElement();
127
128
        // Return
129 105
        return $objWriter->getData();
130
    }
131
132
    /**
133
     * Write SheetPr.
134
     *
135
     * @param XMLWriter $objWriter XML Writer
136
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
137
     */
138 105
    private function writeSheetPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
139
    {
140
        // sheetPr
141 105
        $objWriter->startElement('sheetPr');
142 105
        if ($pSheet->getParent()->hasMacros()) {
143
            //if the workbook have macros, we need to have codeName for the sheet
144 1
            if (!$pSheet->hasCodeName()) {
145
                $pSheet->setCodeName($pSheet->getTitle());
146
            }
147 1
            $objWriter->writeAttribute('codeName', $pSheet->getCodeName());
148
        }
149 105
        $autoFilterRange = $pSheet->getAutoFilter()->getRange();
150 105
        if (!empty($autoFilterRange)) {
151 3
            $objWriter->writeAttribute('filterMode', 1);
152 3
            $pSheet->getAutoFilter()->showHideRows();
153
        }
154
155
        // tabColor
156 105
        if ($pSheet->isTabColorSet()) {
157 6
            $objWriter->startElement('tabColor');
158 6
            $objWriter->writeAttribute('rgb', $pSheet->getTabColor()->getARGB());
159 6
            $objWriter->endElement();
160
        }
161
162
        // outlinePr
163 105
        $objWriter->startElement('outlinePr');
164 105
        $objWriter->writeAttribute('summaryBelow', ($pSheet->getShowSummaryBelow() ? '1' : '0'));
165 105
        $objWriter->writeAttribute('summaryRight', ($pSheet->getShowSummaryRight() ? '1' : '0'));
166 105
        $objWriter->endElement();
167
168
        // pageSetUpPr
169 105
        if ($pSheet->getPageSetup()->getFitToPage()) {
170
            $objWriter->startElement('pageSetUpPr');
171
            $objWriter->writeAttribute('fitToPage', '1');
172
            $objWriter->endElement();
173
        }
174
175 105
        $objWriter->endElement();
176 105
    }
177
178
    /**
179
     * Write Dimension.
180
     *
181
     * @param XMLWriter $objWriter XML Writer
182
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
183
     */
184 105
    private function writeDimension(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
185
    {
186
        // dimension
187 105
        $objWriter->startElement('dimension');
188 105
        $objWriter->writeAttribute('ref', $pSheet->calculateWorksheetDimension());
189 105
        $objWriter->endElement();
190 105
    }
191
192
    /**
193
     * Write SheetViews.
194
     *
195
     * @param XMLWriter $objWriter XML Writer
196
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
197
     *
198
     * @throws WriterException
199
     */
200 105
    private function writeSheetViews(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
201
    {
202
        // sheetViews
203 105
        $objWriter->startElement('sheetViews');
204
205
        // Sheet selected?
206 105
        $sheetSelected = false;
207 105
        if ($this->getParentWriter()->getSpreadsheet()->getIndex($pSheet) == $this->getParentWriter()->getSpreadsheet()->getActiveSheetIndex()) {
208 105
            $sheetSelected = true;
209
        }
210
211
        // sheetView
212 105
        $objWriter->startElement('sheetView');
213 105
        $objWriter->writeAttribute('tabSelected', $sheetSelected ? '1' : '0');
214 105
        $objWriter->writeAttribute('workbookViewId', '0');
215
216
        // Zoom scales
217 105
        if ($pSheet->getSheetView()->getZoomScale() != 100) {
218
            $objWriter->writeAttribute('zoomScale', $pSheet->getSheetView()->getZoomScale());
219
        }
220 105
        if ($pSheet->getSheetView()->getZoomScaleNormal() != 100) {
221
            $objWriter->writeAttribute('zoomScaleNormal', $pSheet->getSheetView()->getZoomScaleNormal());
222
        }
223
224
        // Show zeros (Excel also writes this attribute only if set to false)
225 105
        if ($pSheet->getSheetView()->getShowZeros() === false) {
226
            $objWriter->writeAttribute('showZeros', 0);
227
        }
228
229
        // View Layout Type
230 105
        if ($pSheet->getSheetView()->getView() !== SheetView::SHEETVIEW_NORMAL) {
231 1
            $objWriter->writeAttribute('view', $pSheet->getSheetView()->getView());
232
        }
233
234
        // Gridlines
235 105
        if ($pSheet->getShowGridlines()) {
236 105
            $objWriter->writeAttribute('showGridLines', 'true');
237
        } else {
238
            $objWriter->writeAttribute('showGridLines', 'false');
239
        }
240
241
        // Row and column headers
242 105
        if ($pSheet->getShowRowColHeaders()) {
243 105
            $objWriter->writeAttribute('showRowColHeaders', '1');
244
        } else {
245
            $objWriter->writeAttribute('showRowColHeaders', '0');
246
        }
247
248
        // Right-to-left
249 105
        if ($pSheet->getRightToLeft()) {
250
            $objWriter->writeAttribute('rightToLeft', 'true');
251
        }
252
253 105
        $activeCell = $pSheet->getActiveCell();
254 105
        $sqref = $pSheet->getSelectedCells();
255
256
        // Pane
257 105
        $pane = '';
258 105
        if ($pSheet->getFreezePane()) {
259 6
            [$xSplit, $ySplit] = Coordinate::coordinateFromString($pSheet->getFreezePane());
260 6
            $xSplit = Coordinate::columnIndexFromString($xSplit);
261 6
            --$xSplit;
262 6
            --$ySplit;
263
264 6
            $topLeftCell = $pSheet->getTopLeftCell();
265
266
            // pane
267 6
            $pane = 'topRight';
268 6
            $objWriter->startElement('pane');
269 6
            if ($xSplit > 0) {
270 1
                $objWriter->writeAttribute('xSplit', $xSplit);
271
            }
272 6
            if ($ySplit > 0) {
273 6
                $objWriter->writeAttribute('ySplit', $ySplit);
274 6
                $pane = ($xSplit > 0) ? 'bottomRight' : 'bottomLeft';
275
            }
276 6
            $objWriter->writeAttribute('topLeftCell', $topLeftCell);
277 6
            $objWriter->writeAttribute('activePane', $pane);
278 6
            $objWriter->writeAttribute('state', 'frozen');
279 6
            $objWriter->endElement();
280
281 6
            if (($xSplit > 0) && ($ySplit > 0)) {
282
                //    Write additional selections if more than two panes (ie both an X and a Y split)
283 1
                $objWriter->startElement('selection');
284 1
                $objWriter->writeAttribute('pane', 'topRight');
285 1
                $objWriter->endElement();
286 1
                $objWriter->startElement('selection');
287 1
                $objWriter->writeAttribute('pane', 'bottomLeft');
288 1
                $objWriter->endElement();
289
            }
290
        }
291
292
        // Selection
293
        // Only need to write selection element if we have a split pane
294
        // We cheat a little by over-riding the active cell selection, setting it to the split cell
295 105
        $objWriter->startElement('selection');
296 105
        if ($pane != '') {
297 6
            $objWriter->writeAttribute('pane', $pane);
298
        }
299 105
        $objWriter->writeAttribute('activeCell', $activeCell);
300 105
        $objWriter->writeAttribute('sqref', $sqref);
301 105
        $objWriter->endElement();
302
303 105
        $objWriter->endElement();
304
305 105
        $objWriter->endElement();
306 105
    }
307
308
    /**
309
     * Write SheetFormatPr.
310
     *
311
     * @param XMLWriter $objWriter XML Writer
312
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
313
     */
314 105
    private function writeSheetFormatPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
315
    {
316
        // sheetFormatPr
317 105
        $objWriter->startElement('sheetFormatPr');
318
319
        // Default row height
320 105
        if ($pSheet->getDefaultRowDimension()->getRowHeight() >= 0) {
321 3
            $objWriter->writeAttribute('customHeight', 'true');
322 3
            $objWriter->writeAttribute('defaultRowHeight', StringHelper::formatNumber($pSheet->getDefaultRowDimension()->getRowHeight()));
323
        } else {
324 102
            $objWriter->writeAttribute('defaultRowHeight', '14.4');
325
        }
326
327
        // Set Zero Height row
328 105
        if ((string) $pSheet->getDefaultRowDimension()->getZeroHeight() === '1' ||
329 105
            strtolower((string) $pSheet->getDefaultRowDimension()->getZeroHeight()) == 'true') {
330
            $objWriter->writeAttribute('zeroHeight', '1');
331
        }
332
333
        // Default column width
334 105
        if ($pSheet->getDefaultColumnDimension()->getWidth() >= 0) {
335 2
            $objWriter->writeAttribute('defaultColWidth', StringHelper::formatNumber($pSheet->getDefaultColumnDimension()->getWidth()));
336
        }
337
338
        // Outline level - row
339 105
        $outlineLevelRow = 0;
340 105
        foreach ($pSheet->getRowDimensions() as $dimension) {
341 13
            if ($dimension->getOutlineLevel() > $outlineLevelRow) {
342
                $outlineLevelRow = $dimension->getOutlineLevel();
343
            }
344
        }
345 105
        $objWriter->writeAttribute('outlineLevelRow', (int) $outlineLevelRow);
346
347
        // Outline level - column
348 105
        $outlineLevelCol = 0;
349 105
        foreach ($pSheet->getColumnDimensions() as $dimension) {
350 24
            if ($dimension->getOutlineLevel() > $outlineLevelCol) {
351 1
                $outlineLevelCol = $dimension->getOutlineLevel();
352
            }
353
        }
354 105
        $objWriter->writeAttribute('outlineLevelCol', (int) $outlineLevelCol);
355
356 105
        $objWriter->endElement();
357 105
    }
358
359
    /**
360
     * Write Cols.
361
     *
362
     * @param XMLWriter $objWriter XML Writer
363
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
364
     */
365 105
    private function writeCols(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
366
    {
367
        // cols
368 105
        if (count($pSheet->getColumnDimensions()) > 0) {
369 24
            $objWriter->startElement('cols');
370
371 24
            $pSheet->calculateColumnWidths();
372
373
            // Loop through column dimensions
374 24
            foreach ($pSheet->getColumnDimensions() as $colDimension) {
375
                // col
376 24
                $objWriter->startElement('col');
377 24
                $objWriter->writeAttribute('min', Coordinate::columnIndexFromString($colDimension->getColumnIndex()));
378 24
                $objWriter->writeAttribute('max', Coordinate::columnIndexFromString($colDimension->getColumnIndex()));
379
380 24
                if ($colDimension->getWidth() < 0) {
381
                    // No width set, apply default of 10
382 2
                    $objWriter->writeAttribute('width', '9.10');
383
                } else {
384
                    // Width set
385 24
                    $objWriter->writeAttribute('width', StringHelper::formatNumber($colDimension->getWidth()));
386
                }
387
388
                // Column visibility
389 24
                if ($colDimension->getVisible() === false) {
390 3
                    $objWriter->writeAttribute('hidden', 'true');
391
                }
392
393
                // Auto size?
394 24
                if ($colDimension->getAutoSize()) {
395 8
                    $objWriter->writeAttribute('bestFit', 'true');
396
                }
397
398
                // Custom width?
399 24
                if ($colDimension->getWidth() != $pSheet->getDefaultColumnDimension()->getWidth()) {
400 24
                    $objWriter->writeAttribute('customWidth', 'true');
401
                }
402
403
                // Collapsed
404 24
                if ($colDimension->getCollapsed() === true) {
405 1
                    $objWriter->writeAttribute('collapsed', 'true');
406
                }
407
408
                // Outline level
409 24
                if ($colDimension->getOutlineLevel() > 0) {
410 1
                    $objWriter->writeAttribute('outlineLevel', $colDimension->getOutlineLevel());
411
                }
412
413
                // Style
414 24
                $objWriter->writeAttribute('style', $colDimension->getXfIndex());
415
416 24
                $objWriter->endElement();
417
            }
418
419 24
            $objWriter->endElement();
420
        }
421 105
    }
422
423
    /**
424
     * Write SheetProtection.
425
     *
426
     * @param XMLWriter $objWriter XML Writer
427
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
428
     */
429 105
    private function writeSheetProtection(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
430
    {
431
        // sheetProtection
432 105
        $objWriter->startElement('sheetProtection');
433
434 105
        if ($pSheet->getProtection()->getPassword() !== '') {
435 2
            $objWriter->writeAttribute('password', $pSheet->getProtection()->getPassword());
436
        }
437
438 105
        $objWriter->writeAttribute('sheet', ($pSheet->getProtection()->getSheet() ? 'true' : 'false'));
439 105
        $objWriter->writeAttribute('objects', ($pSheet->getProtection()->getObjects() ? 'true' : 'false'));
440 105
        $objWriter->writeAttribute('scenarios', ($pSheet->getProtection()->getScenarios() ? 'true' : 'false'));
441 105
        $objWriter->writeAttribute('formatCells', ($pSheet->getProtection()->getFormatCells() ? 'true' : 'false'));
442 105
        $objWriter->writeAttribute('formatColumns', ($pSheet->getProtection()->getFormatColumns() ? 'true' : 'false'));
443 105
        $objWriter->writeAttribute('formatRows', ($pSheet->getProtection()->getFormatRows() ? 'true' : 'false'));
444 105
        $objWriter->writeAttribute('insertColumns', ($pSheet->getProtection()->getInsertColumns() ? 'true' : 'false'));
445 105
        $objWriter->writeAttribute('insertRows', ($pSheet->getProtection()->getInsertRows() ? 'true' : 'false'));
446 105
        $objWriter->writeAttribute('insertHyperlinks', ($pSheet->getProtection()->getInsertHyperlinks() ? 'true' : 'false'));
447 105
        $objWriter->writeAttribute('deleteColumns', ($pSheet->getProtection()->getDeleteColumns() ? 'true' : 'false'));
448 105
        $objWriter->writeAttribute('deleteRows', ($pSheet->getProtection()->getDeleteRows() ? 'true' : 'false'));
449 105
        $objWriter->writeAttribute('selectLockedCells', ($pSheet->getProtection()->getSelectLockedCells() ? 'true' : 'false'));
450 105
        $objWriter->writeAttribute('sort', ($pSheet->getProtection()->getSort() ? 'true' : 'false'));
451 105
        $objWriter->writeAttribute('autoFilter', ($pSheet->getProtection()->getAutoFilter() ? 'true' : 'false'));
452 105
        $objWriter->writeAttribute('pivotTables', ($pSheet->getProtection()->getPivotTables() ? 'true' : 'false'));
453 105
        $objWriter->writeAttribute('selectUnlockedCells', ($pSheet->getProtection()->getSelectUnlockedCells() ? 'true' : 'false'));
454 105
        $objWriter->endElement();
455 105
    }
456
457
    /**
458
     * Write ConditionalFormatting.
459
     *
460
     * @param XMLWriter $objWriter XML Writer
461
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
462
     *
463
     * @throws WriterException
464
     */
465 105
    private function writeConditionalFormatting(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
466
    {
467
        // Conditional id
468 105
        $id = 1;
469
470
        // Loop through styles in the current worksheet
471 105
        foreach ($pSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
472 5
            foreach ($conditionalStyles as $conditional) {
473
                // WHY was this again?
474
                // if ($this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) == '') {
475
                //    continue;
476
                // }
477 5
                if ($conditional->getConditionType() != Conditional::CONDITION_NONE) {
478
                    // conditionalFormatting
479 5
                    $objWriter->startElement('conditionalFormatting');
480 5
                    $objWriter->writeAttribute('sqref', $cellCoordinate);
481
482
                    // cfRule
483 5
                    $objWriter->startElement('cfRule');
484 5
                    $objWriter->writeAttribute('type', $conditional->getConditionType());
485 5
                    $objWriter->writeAttribute('dxfId', $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()));
486 5
                    $objWriter->writeAttribute('priority', $id++);
487
488 5
                    if (($conditional->getConditionType() == Conditional::CONDITION_CELLIS || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT)
489 5
                        && $conditional->getOperatorType() != Conditional::OPERATOR_NONE) {
490 4
                        $objWriter->writeAttribute('operator', $conditional->getOperatorType());
491
                    }
492
493 5
                    if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
494 5
                        && $conditional->getText() !== null) {
495
                        $objWriter->writeAttribute('text', $conditional->getText());
496
                    }
497
498 5
                    if ($conditional->getStopIfTrue()) {
499 1
                        $objWriter->writeAttribute('stopIfTrue', '1');
500
                    }
501
502 5
                    if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
503 5
                        && $conditional->getOperatorType() == Conditional::OPERATOR_CONTAINSTEXT
504 5
                        && $conditional->getText() !== null) {
505
                        $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . ')))');
506 5
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
507 5
                        && $conditional->getOperatorType() == Conditional::OPERATOR_BEGINSWITH
508 5
                        && $conditional->getText() !== null) {
509
                        $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"');
510 5
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
511 5
                        && $conditional->getOperatorType() == Conditional::OPERATOR_ENDSWITH
512 5
                        && $conditional->getText() !== null) {
513
                        $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"');
514 5
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
515 5
                        && $conditional->getOperatorType() == Conditional::OPERATOR_NOTCONTAINS
516 5
                        && $conditional->getText() !== null) {
517
                        $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . '))');
518 5
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS
519 5
                        || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
520 5
                        || $conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
521 4
                        foreach ($conditional->getConditions() as $formula) {
522
                            // Formula
523 4
                            $objWriter->writeElement('formula', $formula);
524
                        }
525 2
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSBLANKS) {
526
                        // formula copied from ms xlsx xml source file
527 2
                        $objWriter->writeElement('formula', 'LEN(TRIM(' . $cellCoordinate . '))=0');
528 1
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_NOTCONTAINSBLANKS) {
529
                        // formula copied from ms xlsx xml source file
530 1
                        $objWriter->writeElement('formula', 'LEN(TRIM(' . $cellCoordinate . '))>0');
531
                    }
532
533 5
                    $objWriter->endElement();
534
535 5
                    $objWriter->endElement();
536
                }
537
            }
538
        }
539 105
    }
540
541
    /**
542
     * Write DataValidations.
543
     *
544
     * @param XMLWriter $objWriter XML Writer
545
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
546
     */
547 105
    private function writeDataValidations(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
548
    {
549
        // Datavalidation collection
550 105
        $dataValidationCollection = $pSheet->getDataValidationCollection();
551
552
        // Write data validations?
553 105
        if (!empty($dataValidationCollection)) {
554 2
            $dataValidationCollection = Coordinate::mergeRangesInCollection($dataValidationCollection);
555 2
            $objWriter->startElement('dataValidations');
556 2
            $objWriter->writeAttribute('count', count($dataValidationCollection));
557
558 2
            foreach ($dataValidationCollection as $coordinate => $dv) {
559 2
                $objWriter->startElement('dataValidation');
560
561 2
                if ($dv->getType() != '') {
562 2
                    $objWriter->writeAttribute('type', $dv->getType());
563
                }
564
565 2
                if ($dv->getErrorStyle() != '') {
566 2
                    $objWriter->writeAttribute('errorStyle', $dv->getErrorStyle());
567
                }
568
569 2
                if ($dv->getOperator() != '') {
570 2
                    $objWriter->writeAttribute('operator', $dv->getOperator());
571
                }
572
573 2
                $objWriter->writeAttribute('allowBlank', ($dv->getAllowBlank() ? '1' : '0'));
574 2
                $objWriter->writeAttribute('showDropDown', (!$dv->getShowDropDown() ? '1' : '0'));
575 2
                $objWriter->writeAttribute('showInputMessage', ($dv->getShowInputMessage() ? '1' : '0'));
576 2
                $objWriter->writeAttribute('showErrorMessage', ($dv->getShowErrorMessage() ? '1' : '0'));
577
578 2
                if ($dv->getErrorTitle() !== '') {
579 2
                    $objWriter->writeAttribute('errorTitle', $dv->getErrorTitle());
580
                }
581 2
                if ($dv->getError() !== '') {
582 2
                    $objWriter->writeAttribute('error', $dv->getError());
583
                }
584 2
                if ($dv->getPromptTitle() !== '') {
585 2
                    $objWriter->writeAttribute('promptTitle', $dv->getPromptTitle());
586
                }
587 2
                if ($dv->getPrompt() !== '') {
588 2
                    $objWriter->writeAttribute('prompt', $dv->getPrompt());
589
                }
590
591 2
                $objWriter->writeAttribute('sqref', $coordinate);
592
593 2
                if ($dv->getFormula1() !== '') {
594 2
                    $objWriter->writeElement('formula1', $dv->getFormula1());
595
                }
596 2
                if ($dv->getFormula2() !== '') {
597 1
                    $objWriter->writeElement('formula2', $dv->getFormula2());
598
                }
599
600 2
                $objWriter->endElement();
601
            }
602
603 2
            $objWriter->endElement();
604
        }
605 105
    }
606
607
    /**
608
     * Write Hyperlinks.
609
     *
610
     * @param XMLWriter $objWriter XML Writer
611
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
612
     */
613 105
    private function writeHyperlinks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
614
    {
615
        // Hyperlink collection
616 105
        $hyperlinkCollection = $pSheet->getHyperlinkCollection();
617
618
        // Relation ID
619 105
        $relationId = 1;
620
621
        // Write hyperlinks?
622 105
        if (!empty($hyperlinkCollection)) {
623 10
            $objWriter->startElement('hyperlinks');
624
625 10
            foreach ($hyperlinkCollection as $coordinate => $hyperlink) {
626 10
                $objWriter->startElement('hyperlink');
627
628 10
                $objWriter->writeAttribute('ref', $coordinate);
629 10
                if (!$hyperlink->isInternal()) {
630 10
                    $objWriter->writeAttribute('r:id', 'rId_hyperlink_' . $relationId);
631 10
                    ++$relationId;
632
                } else {
633 7
                    $objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl()));
634
                }
635
636 10
                if ($hyperlink->getTooltip() !== '') {
637 6
                    $objWriter->writeAttribute('tooltip', $hyperlink->getTooltip());
638 6
                    $objWriter->writeAttribute('display', $hyperlink->getTooltip());
639
                }
640
641 10
                $objWriter->endElement();
642
            }
643
644 10
            $objWriter->endElement();
645
        }
646 105
    }
647
648
    /**
649
     * Write ProtectedRanges.
650
     *
651
     * @param XMLWriter $objWriter XML Writer
652
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
653
     */
654 105
    private function writeProtectedRanges(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
655
    {
656 105
        if (count($pSheet->getProtectedCells()) > 0) {
657
            // protectedRanges
658 6
            $objWriter->startElement('protectedRanges');
659
660
            // Loop protectedRanges
661 6
            foreach ($pSheet->getProtectedCells() as $protectedCell => $passwordHash) {
662
                // protectedRange
663 6
                $objWriter->startElement('protectedRange');
664 6
                $objWriter->writeAttribute('name', 'p' . md5($protectedCell));
665 6
                $objWriter->writeAttribute('sqref', $protectedCell);
666 6
                if (!empty($passwordHash)) {
667 6
                    $objWriter->writeAttribute('password', $passwordHash);
0 ignored issues
show
Bug introduced by
$passwordHash of type array is incompatible with the type string expected by parameter $value of XMLWriter::writeAttribute(). ( Ignorable by Annotation )

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

667
                    $objWriter->writeAttribute('password', /** @scrutinizer ignore-type */ $passwordHash);
Loading history...
668
                }
669 6
                $objWriter->endElement();
670
            }
671
672 6
            $objWriter->endElement();
673
        }
674 105
    }
675
676
    /**
677
     * Write MergeCells.
678
     *
679
     * @param XMLWriter $objWriter XML Writer
680
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
681
     */
682 105
    private function writeMergeCells(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
683
    {
684 105
        if (count($pSheet->getMergeCells()) > 0) {
685
            // mergeCells
686 13
            $objWriter->startElement('mergeCells');
687
688
            // Loop mergeCells
689 13
            foreach ($pSheet->getMergeCells() as $mergeCell) {
690
                // mergeCell
691 13
                $objWriter->startElement('mergeCell');
692 13
                $objWriter->writeAttribute('ref', $mergeCell);
0 ignored issues
show
Bug introduced by
$mergeCell of type array is incompatible with the type string expected by parameter $value of XMLWriter::writeAttribute(). ( Ignorable by Annotation )

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

692
                $objWriter->writeAttribute('ref', /** @scrutinizer ignore-type */ $mergeCell);
Loading history...
693 13
                $objWriter->endElement();
694
            }
695
696 13
            $objWriter->endElement();
697
        }
698 105
    }
699
700
    /**
701
     * Write PrintOptions.
702
     *
703
     * @param XMLWriter $objWriter XML Writer
704
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
705
     */
706 105
    private function writePrintOptions(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
707
    {
708
        // printOptions
709 105
        $objWriter->startElement('printOptions');
710
711 105
        $objWriter->writeAttribute('gridLines', ($pSheet->getPrintGridlines() ? 'true' : 'false'));
712 105
        $objWriter->writeAttribute('gridLinesSet', 'true');
713
714 105
        if ($pSheet->getPageSetup()->getHorizontalCentered()) {
715
            $objWriter->writeAttribute('horizontalCentered', 'true');
716
        }
717
718 105
        if ($pSheet->getPageSetup()->getVerticalCentered()) {
719
            $objWriter->writeAttribute('verticalCentered', 'true');
720
        }
721
722 105
        $objWriter->endElement();
723 105
    }
724
725
    /**
726
     * Write PageMargins.
727
     *
728
     * @param XMLWriter $objWriter XML Writer
729
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
730
     */
731 105
    private function writePageMargins(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
732
    {
733
        // pageMargins
734 105
        $objWriter->startElement('pageMargins');
735 105
        $objWriter->writeAttribute('left', StringHelper::formatNumber($pSheet->getPageMargins()->getLeft()));
736 105
        $objWriter->writeAttribute('right', StringHelper::formatNumber($pSheet->getPageMargins()->getRight()));
737 105
        $objWriter->writeAttribute('top', StringHelper::formatNumber($pSheet->getPageMargins()->getTop()));
738 105
        $objWriter->writeAttribute('bottom', StringHelper::formatNumber($pSheet->getPageMargins()->getBottom()));
739 105
        $objWriter->writeAttribute('header', StringHelper::formatNumber($pSheet->getPageMargins()->getHeader()));
740 105
        $objWriter->writeAttribute('footer', StringHelper::formatNumber($pSheet->getPageMargins()->getFooter()));
741 105
        $objWriter->endElement();
742 105
    }
743
744
    /**
745
     * Write AutoFilter.
746
     *
747
     * @param XMLWriter $objWriter XML Writer
748
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
749
     */
750 105
    private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
751
    {
752 105
        $autoFilterRange = $pSheet->getAutoFilter()->getRange();
753 105
        if (!empty($autoFilterRange)) {
754
            // autoFilter
755 3
            $objWriter->startElement('autoFilter');
756
757
            // Strip any worksheet reference from the filter coordinates
758 3
            $range = Coordinate::splitRange($autoFilterRange);
759 3
            $range = $range[0];
760
            //    Strip any worksheet ref
761 3
            [$ws, $range[0]] = PhpspreadsheetWorksheet::extractSheetTitle($range[0], true);
762 3
            $range = implode(':', $range);
763
764 3
            $objWriter->writeAttribute('ref', str_replace('$', '', $range));
765
766 3
            $columns = $pSheet->getAutoFilter()->getColumns();
767 3
            if (count($columns) > 0) {
768 2
                foreach ($columns as $columnID => $column) {
769 2
                    $rules = $column->getRules();
770 2
                    if (count($rules) > 0) {
771 2
                        $objWriter->startElement('filterColumn');
772 2
                        $objWriter->writeAttribute('colId', $pSheet->getAutoFilter()->getColumnOffset($columnID));
773
774 2
                        $objWriter->startElement($column->getFilterType());
775 2
                        if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) {
776 1
                            $objWriter->writeAttribute('and', 1);
777
                        }
778
779 2
                        foreach ($rules as $rule) {
780 2
                            if (($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) &&
781 2
                                ($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) &&
782 2
                                ($rule->getValue() === '')) {
783
                                //    Filter rule for Blanks
784 1
                                $objWriter->writeAttribute('blank', 1);
785 2
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) {
786
                                //    Dynamic Filter Rule
787 1
                                $objWriter->writeAttribute('type', $rule->getGrouping());
788 1
                                $val = $column->getAttribute('val');
789 1
                                if ($val !== null) {
790 1
                                    $objWriter->writeAttribute('val', $val);
791
                                }
792 1
                                $maxVal = $column->getAttribute('maxVal');
793 1
                                if ($maxVal !== null) {
794 1
                                    $objWriter->writeAttribute('maxVal', $maxVal);
795
                                }
796 2
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) {
797
                                //    Top 10 Filter Rule
798
                                $objWriter->writeAttribute('val', $rule->getValue());
799
                                $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0'));
800
                                $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0'));
801
                            } else {
802
                                //    Filter, DateGroupItem or CustomFilter
803 2
                                $objWriter->startElement($rule->getRuleType());
804
805 2
                                if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) {
806 1
                                    $objWriter->writeAttribute('operator', $rule->getOperator());
807
                                }
808 2
                                if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) {
809
                                    // Date Group filters
810 1
                                    foreach ($rule->getValue() as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $rule->getValue() of type string is not traversable.
Loading history...
811 1
                                        if ($value > '') {
812 1
                                            $objWriter->writeAttribute($key, $value);
813
                                        }
814
                                    }
815 1
                                    $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping());
816
                                } else {
817 2
                                    $objWriter->writeAttribute('val', $rule->getValue());
818
                                }
819
820 2
                                $objWriter->endElement();
821
                            }
822
                        }
823
824 2
                        $objWriter->endElement();
825
826 2
                        $objWriter->endElement();
827
                    }
828
                }
829
            }
830 3
            $objWriter->endElement();
831
        }
832 105
    }
833
834
    /**
835
     * Write PageSetup.
836
     *
837
     * @param XMLWriter $objWriter XML Writer
838
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
839
     */
840 105
    private function writePageSetup(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
841
    {
842
        // pageSetup
843 105
        $objWriter->startElement('pageSetup');
844 105
        $objWriter->writeAttribute('paperSize', $pSheet->getPageSetup()->getPaperSize());
845 105
        $objWriter->writeAttribute('orientation', $pSheet->getPageSetup()->getOrientation());
846
847 105
        if ($pSheet->getPageSetup()->getScale() !== null) {
0 ignored issues
show
introduced by
The condition $pSheet->getPageSetup()->getScale() !== null is always true.
Loading history...
848 105
            $objWriter->writeAttribute('scale', $pSheet->getPageSetup()->getScale());
849
        }
850 105
        if ($pSheet->getPageSetup()->getFitToHeight() !== null) {
0 ignored issues
show
introduced by
The condition $pSheet->getPageSetup()-...tFitToHeight() !== null is always true.
Loading history...
851 105
            $objWriter->writeAttribute('fitToHeight', $pSheet->getPageSetup()->getFitToHeight());
852
        } else {
853
            $objWriter->writeAttribute('fitToHeight', '0');
854
        }
855 105
        if ($pSheet->getPageSetup()->getFitToWidth() !== null) {
0 ignored issues
show
introduced by
The condition $pSheet->getPageSetup()->getFitToWidth() !== null is always true.
Loading history...
856 105
            $objWriter->writeAttribute('fitToWidth', $pSheet->getPageSetup()->getFitToWidth());
857
        } else {
858
            $objWriter->writeAttribute('fitToWidth', '0');
859
        }
860 105
        if ($pSheet->getPageSetup()->getFirstPageNumber() !== null) {
0 ignored issues
show
introduced by
The condition $pSheet->getPageSetup()-...stPageNumber() !== null is always true.
Loading history...
861
            $objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber());
862
            $objWriter->writeAttribute('useFirstPageNumber', '1');
863
        }
864
865 105
        $getUnparsedLoadedData = $pSheet->getParent()->getUnparsedLoadedData();
866 105
        if (isset($getUnparsedLoadedData['sheets'][$pSheet->getCodeName()]['pageSetupRelId'])) {
867 4
            $objWriter->writeAttribute('r:id', $getUnparsedLoadedData['sheets'][$pSheet->getCodeName()]['pageSetupRelId']);
868
        }
869
870 105
        $objWriter->endElement();
871 105
    }
872
873
    /**
874
     * Write Header / Footer.
875
     *
876
     * @param XMLWriter $objWriter XML Writer
877
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
878
     */
879 105
    private function writeHeaderFooter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
880
    {
881
        // headerFooter
882 105
        $objWriter->startElement('headerFooter');
883 105
        $objWriter->writeAttribute('differentOddEven', ($pSheet->getHeaderFooter()->getDifferentOddEven() ? 'true' : 'false'));
884 105
        $objWriter->writeAttribute('differentFirst', ($pSheet->getHeaderFooter()->getDifferentFirst() ? 'true' : 'false'));
885 105
        $objWriter->writeAttribute('scaleWithDoc', ($pSheet->getHeaderFooter()->getScaleWithDocument() ? 'true' : 'false'));
886 105
        $objWriter->writeAttribute('alignWithMargins', ($pSheet->getHeaderFooter()->getAlignWithMargins() ? 'true' : 'false'));
887
888 105
        $objWriter->writeElement('oddHeader', $pSheet->getHeaderFooter()->getOddHeader());
889 105
        $objWriter->writeElement('oddFooter', $pSheet->getHeaderFooter()->getOddFooter());
890 105
        $objWriter->writeElement('evenHeader', $pSheet->getHeaderFooter()->getEvenHeader());
891 105
        $objWriter->writeElement('evenFooter', $pSheet->getHeaderFooter()->getEvenFooter());
892 105
        $objWriter->writeElement('firstHeader', $pSheet->getHeaderFooter()->getFirstHeader());
893 105
        $objWriter->writeElement('firstFooter', $pSheet->getHeaderFooter()->getFirstFooter());
894 105
        $objWriter->endElement();
895 105
    }
896
897
    /**
898
     * Write Breaks.
899
     *
900
     * @param XMLWriter $objWriter XML Writer
901
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
902
     */
903 105
    private function writeBreaks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
904
    {
905
        // Get row and column breaks
906 105
        $aRowBreaks = [];
907 105
        $aColumnBreaks = [];
908 105
        foreach ($pSheet->getBreaks() as $cell => $breakType) {
909 1
            if ($breakType == PhpspreadsheetWorksheet::BREAK_ROW) {
910 1
                $aRowBreaks[] = $cell;
911
            } elseif ($breakType == PhpspreadsheetWorksheet::BREAK_COLUMN) {
912
                $aColumnBreaks[] = $cell;
913
            }
914
        }
915
916
        // rowBreaks
917 105
        if (!empty($aRowBreaks)) {
918 1
            $objWriter->startElement('rowBreaks');
919 1
            $objWriter->writeAttribute('count', count($aRowBreaks));
920 1
            $objWriter->writeAttribute('manualBreakCount', count($aRowBreaks));
921
922 1
            foreach ($aRowBreaks as $cell) {
923 1
                $coords = Coordinate::coordinateFromString($cell);
924
925 1
                $objWriter->startElement('brk');
926 1
                $objWriter->writeAttribute('id', $coords[1]);
927 1
                $objWriter->writeAttribute('man', '1');
928 1
                $objWriter->endElement();
929
            }
930
931 1
            $objWriter->endElement();
932
        }
933
934
        // Second, write column breaks
935 105
        if (!empty($aColumnBreaks)) {
936
            $objWriter->startElement('colBreaks');
937
            $objWriter->writeAttribute('count', count($aColumnBreaks));
938
            $objWriter->writeAttribute('manualBreakCount', count($aColumnBreaks));
939
940
            foreach ($aColumnBreaks as $cell) {
941
                $coords = Coordinate::coordinateFromString($cell);
942
943
                $objWriter->startElement('brk');
944
                $objWriter->writeAttribute('id', Coordinate::columnIndexFromString($coords[0]) - 1);
945
                $objWriter->writeAttribute('man', '1');
946
                $objWriter->endElement();
947
            }
948
949
            $objWriter->endElement();
950
        }
951 105
    }
952
953
    /**
954
     * Write SheetData.
955
     *
956
     * @param XMLWriter $objWriter XML Writer
957
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
958
     * @param string[] $pStringTable String table
959
     *
960
     * @throws WriterException
961
     */
962 105
    private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, array $pStringTable)
963
    {
964
        // Flipped stringtable, for faster index searching
965 105
        $aFlippedStringTable = $this->getParentWriter()->getWriterPart('stringtable')->flipStringTable($pStringTable);
0 ignored issues
show
Bug introduced by
The method flipStringTable() does not exist on PhpOffice\PhpSpreadsheet\Writer\Xlsx\WriterPart. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\Writer\Xlsx\WriterPart such as PhpOffice\PhpSpreadsheet\Writer\Xlsx\StringTable. ( Ignorable by Annotation )

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

965
        $aFlippedStringTable = $this->getParentWriter()->getWriterPart('stringtable')->/** @scrutinizer ignore-call */ flipStringTable($pStringTable);
Loading history...
966
967
        // sheetData
968 105
        $objWriter->startElement('sheetData');
969
970
        // Get column count
971 105
        $colCount = Coordinate::columnIndexFromString($pSheet->getHighestColumn());
972
973
        // Highest row number
974 105
        $highestRow = $pSheet->getHighestRow();
975
976
        // Loop through cells
977 105
        $cellsByRow = [];
978 105
        foreach ($pSheet->getCoordinates() as $coordinate) {
979 99
            $cellAddress = Coordinate::coordinateFromString($coordinate);
980 99
            $cellsByRow[$cellAddress[1]][] = $coordinate;
981
        }
982
983 105
        $currentRow = 0;
984 105
        while ($currentRow++ < $highestRow) {
985
            // Get row dimension
986 105
            $rowDimension = $pSheet->getRowDimension($currentRow);
987
988
            // Write current row?
989 105
            $writeCurrentRow = isset($cellsByRow[$currentRow]) || $rowDimension->getRowHeight() >= 0 || $rowDimension->getVisible() == false || $rowDimension->getCollapsed() == true || $rowDimension->getOutlineLevel() > 0 || $rowDimension->getXfIndex() !== null;
0 ignored issues
show
introduced by
The condition $rowDimension->getXfIndex() !== null is always true.
Loading history...
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
990
991 105
            if ($writeCurrentRow) {
992
                // Start a new row
993 99
                $objWriter->startElement('row');
994 99
                $objWriter->writeAttribute('r', $currentRow);
995 99
                $objWriter->writeAttribute('spans', '1:' . $colCount);
996
997
                // Row dimensions
998 99
                if ($rowDimension->getRowHeight() >= 0) {
999 6
                    $objWriter->writeAttribute('customHeight', '1');
1000 6
                    $objWriter->writeAttribute('ht', StringHelper::formatNumber($rowDimension->getRowHeight()));
1001
                }
1002
1003
                // Row visibility
1004 99
                if (!$rowDimension->getVisible() === true) {
1005 2
                    $objWriter->writeAttribute('hidden', 'true');
1006
                }
1007
1008
                // Collapsed
1009 99
                if ($rowDimension->getCollapsed() === true) {
1010
                    $objWriter->writeAttribute('collapsed', 'true');
1011
                }
1012
1013
                // Outline level
1014 99
                if ($rowDimension->getOutlineLevel() > 0) {
1015
                    $objWriter->writeAttribute('outlineLevel', $rowDimension->getOutlineLevel());
1016
                }
1017
1018
                // Style
1019 99
                if ($rowDimension->getXfIndex() !== null) {
1020
                    $objWriter->writeAttribute('s', $rowDimension->getXfIndex());
1021
                    $objWriter->writeAttribute('customFormat', '1');
1022
                }
1023
1024
                // Write cells
1025 99
                if (isset($cellsByRow[$currentRow])) {
1026 99
                    foreach ($cellsByRow[$currentRow] as $cellAddress) {
1027
                        // Write cell
1028 99
                        $this->writeCell($objWriter, $pSheet, $cellAddress, $aFlippedStringTable);
1029
                    }
1030
                }
1031
1032
                // End row
1033 99
                $objWriter->endElement();
1034
            }
1035
        }
1036
1037 105
        $objWriter->endElement();
1038 105
    }
1039
1040
    /**
1041
     * Write Cell.
1042
     *
1043
     * @param XMLWriter $objWriter XML Writer
1044
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1045
     * @param Cell $pCellAddress Cell Address
1046
     * @param string[] $pFlippedStringTable String table (flipped), for faster index searching
1047
     *
1048
     * @throws WriterException
1049
     */
1050 99
    private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, $pCellAddress, array $pFlippedStringTable)
1051
    {
1052
        // Cell
1053 99
        $pCell = $pSheet->getCell($pCellAddress);
1054 99
        $objWriter->startElement('c');
1055 99
        $objWriter->writeAttribute('r', $pCellAddress);
1056
1057
        // Sheet styles
1058 99
        if ($pCell->getXfIndex() != '') {
1059 33
            $objWriter->writeAttribute('s', $pCell->getXfIndex());
1060
        }
1061
1062
        // If cell value is supplied, write cell value
1063 99
        $cellValue = $pCell->getValue();
1064 99
        if (is_object($cellValue) || $cellValue !== '') {
1065
            // Map type
1066 99
            $mappedType = $pCell->getDataType();
1067
1068
            // Write data type depending on its type
1069 99
            switch (strtolower($mappedType)) {
1070 99
                case 'inlinestr':    // Inline string
1071 98
                case 's':            // String
1072 82
                case 'b':            // Boolean
1073 66
                    $objWriter->writeAttribute('t', $mappedType);
1074
1075 66
                    break;
1076 79
                case 'f':            // Formula
1077 22
                    $calculatedValue = ($this->getParentWriter()->getPreCalculateFormulas()) ?
1078 22
                        $pCell->getCalculatedValue() : $cellValue;
1079 22
                    if (is_string($calculatedValue)) {
1080 14
                        $objWriter->writeAttribute('t', 'str');
1081 19
                    } elseif (is_bool($calculatedValue)) {
1082 5
                        $objWriter->writeAttribute('t', 'b');
1083
                    }
1084
1085 22
                    break;
1086 75
                case 'e':            // Error
1087
                    $objWriter->writeAttribute('t', $mappedType);
1088
            }
1089
1090
            // Write data depending on its type
1091 99
            switch (strtolower($mappedType)) {
1092 99
                case 'inlinestr':    // Inline string
1093 8
                    if (!$cellValue instanceof RichText) {
1094
                        $objWriter->writeElement('t', StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue)));
1095 8
                    } elseif ($cellValue instanceof RichText) {
0 ignored issues
show
introduced by
$cellValue is always a sub-type of PhpOffice\PhpSpreadsheet\RichText\RichText.
Loading history...
1096 8
                        $objWriter->startElement('is');
1097 8
                        $this->getParentWriter()->getWriterPart('stringtable')->writeRichText($objWriter, $cellValue);
0 ignored issues
show
Bug introduced by
The method writeRichText() does not exist on PhpOffice\PhpSpreadsheet\Writer\Xlsx\WriterPart. It seems like you code against a sub-type of PhpOffice\PhpSpreadsheet\Writer\Xlsx\WriterPart such as PhpOffice\PhpSpreadsheet\Writer\Xlsx\StringTable. ( Ignorable by Annotation )

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

1097
                        $this->getParentWriter()->getWriterPart('stringtable')->/** @scrutinizer ignore-call */ writeRichText($objWriter, $cellValue);
Loading history...
1098 8
                        $objWriter->endElement();
1099
                    }
1100
1101 8
                    break;
1102 98
                case 's':            // String
1103 64
                    if (!$cellValue instanceof RichText) {
1104 64
                        if (isset($pFlippedStringTable[$cellValue])) {
1105 64
                            $objWriter->writeElement('v', $pFlippedStringTable[$cellValue]);
1106
                        }
1107 2
                    } elseif ($cellValue instanceof RichText) {
0 ignored issues
show
introduced by
$cellValue is always a sub-type of PhpOffice\PhpSpreadsheet\RichText\RichText.
Loading history...
1108 2
                        $objWriter->writeElement('v', $pFlippedStringTable[$cellValue->getHashCode()]);
1109
                    }
1110
1111 64
                    break;
1112 82
                case 'f':            // Formula
1113 22
                    $attributes = $pCell->getFormulaAttributes();
1114 22
                    if (($attributes['t'] ?? null) === 'array') {
1115
                        $objWriter->startElement('f');
1116
                        $objWriter->writeAttribute('t', 'array');
1117
                        $objWriter->writeAttribute('ref', $pCellAddress);
1118
                        $objWriter->writeAttribute('aca', '1');
1119
                        $objWriter->writeAttribute('ca', '1');
1120
                        $objWriter->text(substr($cellValue, 1));
1121
                        $objWriter->endElement();
1122
                    } else {
1123 22
                        $objWriter->writeElement('f', substr($cellValue, 1));
1124
                    }
1125 22
                    if ($this->getParentWriter()->getOffice2003Compatibility() === false) {
1126 22
                        if ($this->getParentWriter()->getPreCalculateFormulas()) {
1127 22
                            if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) !== '#') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $calculatedValue does not seem to be defined for all execution paths leading up to this point.
Loading history...
1128 22
                                $objWriter->writeElement('v', StringHelper::formatNumber($calculatedValue));
1129
                            } else {
1130 22
                                $objWriter->writeElement('v', '0');
1131
                            }
1132
                        } else {
1133
                            $objWriter->writeElement('v', '0');
1134
                        }
1135
                    }
1136
1137 22
                    break;
1138 78
                case 'n':            // Numeric
1139
                    //force a decimal to be written if the type is float
1140 67
                    if (is_float($cellValue)) {
1141
                        // force point as decimal separator in case current locale uses comma
1142 28
                        $cellValue = str_replace(',', '.', (string) $cellValue);
1143 28
                        if (strpos($cellValue, '.') === false) {
1144 17
                            $cellValue = $cellValue . '.0';
1145
                        }
1146
                    }
1147 67
                    $objWriter->writeElement('v', $cellValue);
1148
1149 67
                    break;
1150 29
                case 'b':            // Boolean
1151 9
                    $objWriter->writeElement('v', ($cellValue ? '1' : '0'));
1152
1153 9
                    break;
1154 24
                case 'e':            // Error
1155
                    if (substr($cellValue, 0, 1) === '=') {
1156
                        $objWriter->writeElement('f', substr($cellValue, 1));
1157
                        $objWriter->writeElement('v', substr($cellValue, 1));
1158
                    } else {
1159
                        $objWriter->writeElement('v', $cellValue);
1160
                    }
1161
1162
                    break;
1163
            }
1164
        }
1165
1166 99
        $objWriter->endElement();
1167 99
    }
1168
1169
    /**
1170
     * Write Drawings.
1171
     *
1172
     * @param XMLWriter $objWriter XML Writer
1173
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1174
     * @param bool $includeCharts Flag indicating if we should include drawing details for charts
1175
     */
1176 105
    private function writeDrawings(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, $includeCharts = false)
1177
    {
1178 105
        $unparsedLoadedData = $pSheet->getParent()->getUnparsedLoadedData();
1179 105
        $hasUnparsedDrawing = isset($unparsedLoadedData['sheets'][$pSheet->getCodeName()]['drawingOriginalIds']);
1180 105
        $chartCount = ($includeCharts) ? $pSheet->getChartCollection()->count() : 0;
1181 105
        if ($chartCount == 0 && $pSheet->getDrawingCollection()->count() == 0 && !$hasUnparsedDrawing) {
1182 80
            return;
1183
        }
1184
1185
        // If sheet contains drawings, add the relationships
1186 27
        $objWriter->startElement('drawing');
1187
1188 27
        $rId = 'rId1';
1189 27
        if (isset($unparsedLoadedData['sheets'][$pSheet->getCodeName()]['drawingOriginalIds'])) {
1190 4
            $drawingOriginalIds = $unparsedLoadedData['sheets'][$pSheet->getCodeName()]['drawingOriginalIds'];
1191
            // take first. In future can be overriten
1192 4
            $rId = reset($drawingOriginalIds);
1193
        }
1194
1195 27
        $objWriter->writeAttribute('r:id', $rId);
1196 27
        $objWriter->endElement();
1197 27
    }
1198
1199
    /**
1200
     * Write LegacyDrawing.
1201
     *
1202
     * @param XMLWriter $objWriter XML Writer
1203
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1204
     */
1205 105
    private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
1206
    {
1207
        // If sheet contains comments, add the relationships
1208 105
        if (count($pSheet->getComments()) > 0) {
1209 10
            $objWriter->startElement('legacyDrawing');
1210 10
            $objWriter->writeAttribute('r:id', 'rId_comments_vml1');
1211 10
            $objWriter->endElement();
1212
        }
1213 105
    }
1214
1215
    /**
1216
     * Write LegacyDrawingHF.
1217
     *
1218
     * @param XMLWriter $objWriter XML Writer
1219
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1220
     */
1221 105
    private function writeLegacyDrawingHF(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
1222
    {
1223
        // If sheet contains images, add the relationships
1224 105
        if (count($pSheet->getHeaderFooter()->getImages()) > 0) {
1225 1
            $objWriter->startElement('legacyDrawingHF');
1226 1
            $objWriter->writeAttribute('r:id', 'rId_headerfooter_vml1');
1227 1
            $objWriter->endElement();
1228
        }
1229 105
    }
1230
1231 105
    private function writeAlternateContent(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
1232
    {
1233 105
        if (empty($pSheet->getParent()->getUnparsedLoadedData()['sheets'][$pSheet->getCodeName()]['AlternateContents'])) {
1234 105
            return;
1235
        }
1236
1237 1
        foreach ($pSheet->getParent()->getUnparsedLoadedData()['sheets'][$pSheet->getCodeName()]['AlternateContents'] as $alternateContent) {
1238 1
            $objWriter->writeRaw($alternateContent);
1239
        }
1240 1
    }
1241
}
1242