Passed
Push — master ( 955217...cf30c2 )
by Adrien
27:35 queued 19:31
created

Worksheet::writeProtectedRanges()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 4

Importance

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

666
                    $objWriter->writeAttribute('password', /** @scrutinizer ignore-type */ $passwordHash);
Loading history...
667
                }
668 6
                $objWriter->endElement();
669
            }
670
671 6
            $objWriter->endElement();
672
        }
673 100
    }
674
675
    /**
676
     * Write MergeCells.
677
     *
678
     * @param XMLWriter $objWriter XML Writer
679
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
680
     */
681 100
    private function writeMergeCells(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
682
    {
683 100
        if (count($pSheet->getMergeCells()) > 0) {
684
            // mergeCells
685 13
            $objWriter->startElement('mergeCells');
686
687
            // Loop mergeCells
688 13
            foreach ($pSheet->getMergeCells() as $mergeCell) {
689
                // mergeCell
690 13
                $objWriter->startElement('mergeCell');
691 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

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

964
        $aFlippedStringTable = $this->getParentWriter()->getWriterPart('stringtable')->/** @scrutinizer ignore-call */ flipStringTable($pStringTable);
Loading history...
965
966
        // sheetData
967 100
        $objWriter->startElement('sheetData');
968
969
        // Get column count
970 100
        $colCount = Coordinate::columnIndexFromString($pSheet->getHighestColumn());
971
972
        // Highest row number
973 100
        $highestRow = $pSheet->getHighestRow();
974
975
        // Loop through cells
976 100
        $cellsByRow = [];
977 100
        foreach ($pSheet->getCoordinates() as $coordinate) {
978 94
            $cellAddress = Coordinate::coordinateFromString($coordinate);
979 94
            $cellsByRow[$cellAddress[1]][] = $coordinate;
980
        }
981
982 100
        $currentRow = 0;
983 100
        while ($currentRow++ < $highestRow) {
984
            // Get row dimension
985 100
            $rowDimension = $pSheet->getRowDimension($currentRow);
986
987
            // Write current row?
988 100
            $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...
989
990 100
            if ($writeCurrentRow) {
991
                // Start a new row
992 94
                $objWriter->startElement('row');
993 94
                $objWriter->writeAttribute('r', $currentRow);
994 94
                $objWriter->writeAttribute('spans', '1:' . $colCount);
995
996
                // Row dimensions
997 94
                if ($rowDimension->getRowHeight() >= 0) {
998 6
                    $objWriter->writeAttribute('customHeight', '1');
999 6
                    $objWriter->writeAttribute('ht', StringHelper::formatNumber($rowDimension->getRowHeight()));
1000
                }
1001
1002
                // Row visibility
1003 94
                if (!$rowDimension->getVisible() === true) {
1004 2
                    $objWriter->writeAttribute('hidden', 'true');
1005
                }
1006
1007
                // Collapsed
1008 94
                if ($rowDimension->getCollapsed() === true) {
1009
                    $objWriter->writeAttribute('collapsed', 'true');
1010
                }
1011
1012
                // Outline level
1013 94
                if ($rowDimension->getOutlineLevel() > 0) {
1014
                    $objWriter->writeAttribute('outlineLevel', $rowDimension->getOutlineLevel());
1015
                }
1016
1017
                // Style
1018 94
                if ($rowDimension->getXfIndex() !== null) {
1019
                    $objWriter->writeAttribute('s', $rowDimension->getXfIndex());
1020
                    $objWriter->writeAttribute('customFormat', '1');
1021
                }
1022
1023
                // Write cells
1024 94
                if (isset($cellsByRow[$currentRow])) {
1025 94
                    foreach ($cellsByRow[$currentRow] as $cellAddress) {
1026
                        // Write cell
1027 94
                        $this->writeCell($objWriter, $pSheet, $cellAddress, $aFlippedStringTable);
1028
                    }
1029
                }
1030
1031
                // End row
1032 94
                $objWriter->endElement();
1033
            }
1034
        }
1035
1036 100
        $objWriter->endElement();
1037 100
    }
1038
1039
    /**
1040
     * Write Cell.
1041
     *
1042
     * @param XMLWriter $objWriter XML Writer
1043
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1044
     * @param Cell $pCellAddress Cell Address
1045
     * @param string[] $pFlippedStringTable String table (flipped), for faster index searching
1046
     *
1047
     * @throws WriterException
1048
     */
1049 94
    private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, $pCellAddress, array $pFlippedStringTable)
1050
    {
1051
        // Cell
1052 94
        $pCell = $pSheet->getCell($pCellAddress);
1053 94
        $objWriter->startElement('c');
1054 94
        $objWriter->writeAttribute('r', $pCellAddress);
1055
1056
        // Sheet styles
1057 94
        if ($pCell->getXfIndex() != '') {
1058 33
            $objWriter->writeAttribute('s', $pCell->getXfIndex());
1059
        }
1060
1061
        // If cell value is supplied, write cell value
1062 94
        $cellValue = $pCell->getValue();
1063 94
        if (is_object($cellValue) || $cellValue !== '') {
1064
            // Map type
1065 94
            $mappedType = $pCell->getDataType();
1066
1067
            // Write data type depending on its type
1068 94
            switch (strtolower($mappedType)) {
1069 94
                case 'inlinestr':    // Inline string
1070 93
                case 's':            // String
1071 80
                case 'b':            // Boolean
1072 62
                    $objWriter->writeAttribute('t', $mappedType);
1073
1074 62
                    break;
1075 77
                case 'f':            // Formula
1076 22
                    $calculatedValue = ($this->getParentWriter()->getPreCalculateFormulas()) ?
1077 22
                        $pCell->getCalculatedValue() : $cellValue;
1078 22
                    if (is_string($calculatedValue)) {
1079 14
                        $objWriter->writeAttribute('t', 'str');
1080 19
                    } elseif (is_bool($calculatedValue)) {
1081 5
                        $objWriter->writeAttribute('t', 'b');
1082
                    }
1083
1084 22
                    break;
1085 73
                case 'e':            // Error
1086
                    $objWriter->writeAttribute('t', $mappedType);
1087
            }
1088
1089
            // Write data depending on its type
1090 94
            switch (strtolower($mappedType)) {
1091 94
                case 'inlinestr':    // Inline string
1092 8
                    if (!$cellValue instanceof RichText) {
1093
                        $objWriter->writeElement('t', StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue)));
1094 8
                    } elseif ($cellValue instanceof RichText) {
0 ignored issues
show
introduced by
$cellValue is always a sub-type of PhpOffice\PhpSpreadsheet\RichText\RichText.
Loading history...
1095 8
                        $objWriter->startElement('is');
1096 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

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