Failed Conditions
Push — master ( 0c93bb...a2be57 )
by Adrien
29:37 queued 19:11
created

Worksheet::writeSheetData()   F

Complexity

Conditions 16
Paths 782

Size

Total Lines 76
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 16.4163

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 16
eloc 33
c 1
b 0
f 0
nc 782
nop 3
dl 0
loc 76
ccs 30
cts 34
cp 0.8824
crap 16.4163
rs 1.7027

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Settings;
9
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
10
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
11
use PhpOffice\PhpSpreadsheet\Style\Conditional;
12
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalDataBar;
13
use PhpOffice\PhpSpreadsheet\Style\ConditionalFormatting\ConditionalFormattingRuleExtension;
14
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
15
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
16
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView;
17
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet;
18
19
class Worksheet extends WriterPart
20
{
21
    /**
22
     * Write worksheet to XML format.
23
     *
24
     * @param string[] $stringTable
25
     * @param bool $includeCharts Flag indicating if we should write charts
26
     *
27
     * @return string XML Output
28
     */
29 165
    public function writeWorksheet(PhpspreadsheetWorksheet $worksheet, $stringTable = null, $includeCharts = false)
30
    {
31
        // Create XML writer
32 165
        $objWriter = null;
33 165
        if ($this->getParentWriter()->getUseDiskCaching()) {
34
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
35
        } else {
36 165
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
37
        }
38
39
        // XML header
40 165
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
41
42
        // Worksheet
43 165
        $objWriter->startElement('worksheet');
44 165
        $objWriter->writeAttribute('xml:space', 'preserve');
45 165
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
46 165
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
47
48 165
        $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
49 165
        $objWriter->writeAttribute('xmlns:x14', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main');
50 165
        $objWriter->writeAttribute('xmlns:xm', 'http://schemas.microsoft.com/office/excel/2006/main');
51 165
        $objWriter->writeAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006');
52 165
        $objWriter->writeAttribute('mc:Ignorable', 'x14ac');
53 165
        $objWriter->writeAttribute('xmlns:x14ac', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac');
54
55
        // sheetPr
56 165
        $this->writeSheetPr($objWriter, $worksheet);
57
58
        // Dimension
59 165
        $this->writeDimension($objWriter, $worksheet);
60
61
        // sheetViews
62 165
        $this->writeSheetViews($objWriter, $worksheet);
63
64
        // sheetFormatPr
65 165
        $this->writeSheetFormatPr($objWriter, $worksheet);
66
67
        // cols
68 165
        $this->writeCols($objWriter, $worksheet);
69
70
        // sheetData
71 165
        $this->writeSheetData($objWriter, $worksheet, $stringTable);
1 ignored issue
show
Bug introduced by
It seems like $stringTable can also be of type null; however, parameter $stringTable 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

71
        $this->writeSheetData($objWriter, $worksheet, /** @scrutinizer ignore-type */ $stringTable);
Loading history...
72
73
        // sheetProtection
74 165
        $this->writeSheetProtection($objWriter, $worksheet);
75
76
        // protectedRanges
77 165
        $this->writeProtectedRanges($objWriter, $worksheet);
78
79
        // autoFilter
80 165
        $this->writeAutoFilter($objWriter, $worksheet);
81
82
        // mergeCells
83 165
        $this->writeMergeCells($objWriter, $worksheet);
84
85
        // conditionalFormatting
86 165
        $this->writeConditionalFormatting($objWriter, $worksheet);
87
88
        // dataValidations
89 165
        $this->writeDataValidations($objWriter, $worksheet);
90
91
        // hyperlinks
92 165
        $this->writeHyperlinks($objWriter, $worksheet);
93
94
        // Print options
95 165
        $this->writePrintOptions($objWriter, $worksheet);
96
97
        // Page margins
98 165
        $this->writePageMargins($objWriter, $worksheet);
99
100
        // Page setup
101 165
        $this->writePageSetup($objWriter, $worksheet);
102
103
        // Header / footer
104 165
        $this->writeHeaderFooter($objWriter, $worksheet);
105
106
        // Breaks
107 165
        $this->writeBreaks($objWriter, $worksheet);
108
109
        // Drawings and/or Charts
110 165
        $this->writeDrawings($objWriter, $worksheet, $includeCharts);
111
112
        // LegacyDrawing
113 165
        $this->writeLegacyDrawing($objWriter, $worksheet);
114
115
        // LegacyDrawingHF
116 165
        $this->writeLegacyDrawingHF($objWriter, $worksheet);
117
118
        // AlternateContent
119 165
        $this->writeAlternateContent($objWriter, $worksheet);
120
121
        // ConditionalFormattingRuleExtensionList
122
        // (Must be inserted last. Not insert last, an Excel parse error will occur)
123 165
        $this->writeExtLst($objWriter, $worksheet);
124
125 165
        $objWriter->endElement();
126
127
        // Return
128 165
        return $objWriter->getData();
129
    }
130
131
    /**
132
     * Write SheetPr.
133
     */
134 165
    private function writeSheetPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
135
    {
136
        // sheetPr
137 165
        $objWriter->startElement('sheetPr');
138 165
        if ($worksheet->getParent()->hasMacros()) {
139
            //if the workbook have macros, we need to have codeName for the sheet
140 1
            if (!$worksheet->hasCodeName()) {
141
                $worksheet->setCodeName($worksheet->getTitle());
142
            }
143 1
            self::writeAttributeNotNull($objWriter, 'codeName', $worksheet->getCodeName());
144
        }
145 165
        $autoFilterRange = $worksheet->getAutoFilter()->getRange();
146 165
        if (!empty($autoFilterRange)) {
147 4
            $objWriter->writeAttribute('filterMode', 1);
148 4
            $worksheet->getAutoFilter()->showHideRows();
149
        }
150
151
        // tabColor
152 165
        if ($worksheet->isTabColorSet()) {
153 6
            $objWriter->startElement('tabColor');
154 6
            $objWriter->writeAttribute('rgb', $worksheet->getTabColor()->getARGB());
155 6
            $objWriter->endElement();
156
        }
157
158
        // outlinePr
159 165
        $objWriter->startElement('outlinePr');
160 165
        $objWriter->writeAttribute('summaryBelow', ($worksheet->getShowSummaryBelow() ? '1' : '0'));
161 165
        $objWriter->writeAttribute('summaryRight', ($worksheet->getShowSummaryRight() ? '1' : '0'));
162 165
        $objWriter->endElement();
163
164
        // pageSetUpPr
165 165
        if ($worksheet->getPageSetup()->getFitToPage()) {
166
            $objWriter->startElement('pageSetUpPr');
167
            $objWriter->writeAttribute('fitToPage', '1');
168
            $objWriter->endElement();
169
        }
170
171 165
        $objWriter->endElement();
172 165
    }
173
174
    /**
175
     * Write Dimension.
176
     */
177 165
    private function writeDimension(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
178
    {
179
        // dimension
180 165
        $objWriter->startElement('dimension');
181 165
        $objWriter->writeAttribute('ref', $worksheet->calculateWorksheetDimension());
182 165
        $objWriter->endElement();
183 165
    }
184
185
    /**
186
     * Write SheetViews.
187
     */
188 165
    private function writeSheetViews(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
189
    {
190
        // sheetViews
191 165
        $objWriter->startElement('sheetViews');
192
193
        // Sheet selected?
194 165
        $sheetSelected = false;
195 165
        if ($this->getParentWriter()->getSpreadsheet()->getIndex($worksheet) == $this->getParentWriter()->getSpreadsheet()->getActiveSheetIndex()) {
196 165
            $sheetSelected = true;
197
        }
198
199
        // sheetView
200 165
        $objWriter->startElement('sheetView');
201 165
        $objWriter->writeAttribute('tabSelected', $sheetSelected ? '1' : '0');
202 165
        $objWriter->writeAttribute('workbookViewId', '0');
203
204
        // Zoom scales
205 165
        if ($worksheet->getSheetView()->getZoomScale() != 100) {
206
            $objWriter->writeAttribute('zoomScale', $worksheet->getSheetView()->getZoomScale());
207
        }
208 165
        if ($worksheet->getSheetView()->getZoomScaleNormal() != 100) {
209
            $objWriter->writeAttribute('zoomScaleNormal', $worksheet->getSheetView()->getZoomScaleNormal());
210
        }
211
212
        // Show zeros (Excel also writes this attribute only if set to false)
213 165
        if ($worksheet->getSheetView()->getShowZeros() === false) {
214
            $objWriter->writeAttribute('showZeros', 0);
215
        }
216
217
        // View Layout Type
218 165
        if ($worksheet->getSheetView()->getView() !== SheetView::SHEETVIEW_NORMAL) {
219 1
            $objWriter->writeAttribute('view', $worksheet->getSheetView()->getView());
220
        }
221
222
        // Gridlines
223 165
        if ($worksheet->getShowGridlines()) {
224 165
            $objWriter->writeAttribute('showGridLines', 'true');
225
        } else {
226
            $objWriter->writeAttribute('showGridLines', 'false');
227
        }
228
229
        // Row and column headers
230 165
        if ($worksheet->getShowRowColHeaders()) {
231 165
            $objWriter->writeAttribute('showRowColHeaders', '1');
232
        } else {
233
            $objWriter->writeAttribute('showRowColHeaders', '0');
234
        }
235
236
        // Right-to-left
237 165
        if ($worksheet->getRightToLeft()) {
238
            $objWriter->writeAttribute('rightToLeft', 'true');
239
        }
240
241 165
        $topLeftCell = $worksheet->getTopLeftCell();
242 165
        $activeCell = $worksheet->getActiveCell();
243 165
        $sqref = $worksheet->getSelectedCells();
244
245
        // Pane
246 165
        $pane = '';
247 165
        if ($worksheet->getFreezePane()) {
248 6
            [$xSplit, $ySplit] = Coordinate::coordinateFromString($worksheet->getFreezePane() ?? '');
249 6
            $xSplit = Coordinate::columnIndexFromString($xSplit);
250 6
            --$xSplit;
251 6
            --$ySplit;
252
253
            // pane
254 6
            $pane = 'topRight';
255 6
            $objWriter->startElement('pane');
256 6
            if ($xSplit > 0) {
257 1
                $objWriter->writeAttribute('xSplit', $xSplit);
258
            }
259 6
            if ($ySplit > 0) {
260 6
                $objWriter->writeAttribute('ySplit', $ySplit);
261 6
                $pane = ($xSplit > 0) ? 'bottomRight' : 'bottomLeft';
262
            }
263 6
            self::writeAttributeNotNull($objWriter, 'topLeftCell', $topLeftCell);
264 6
            $objWriter->writeAttribute('activePane', $pane);
265 6
            $objWriter->writeAttribute('state', 'frozen');
266 6
            $objWriter->endElement();
267
268 6
            if (($xSplit > 0) && ($ySplit > 0)) {
269
                //    Write additional selections if more than two panes (ie both an X and a Y split)
270 1
                $objWriter->startElement('selection');
271 1
                $objWriter->writeAttribute('pane', 'topRight');
272 1
                $objWriter->endElement();
273 1
                $objWriter->startElement('selection');
274 1
                $objWriter->writeAttribute('pane', 'bottomLeft');
275 6
                $objWriter->endElement();
276
            }
277
        } else {
278 159
            self::writeAttributeNotNull($objWriter, 'topLeftCell', $topLeftCell);
279
        }
280
281
        // Selection
282
        // Only need to write selection element if we have a split pane
283
        // We cheat a little by over-riding the active cell selection, setting it to the split cell
284 165
        $objWriter->startElement('selection');
285 165
        if ($pane != '') {
286 6
            $objWriter->writeAttribute('pane', $pane);
287
        }
288 165
        $objWriter->writeAttribute('activeCell', $activeCell);
289 165
        $objWriter->writeAttribute('sqref', $sqref);
290 165
        $objWriter->endElement();
291
292 165
        $objWriter->endElement();
293
294 165
        $objWriter->endElement();
295 165
    }
296
297
    /**
298
     * Write SheetFormatPr.
299
     */
300 165
    private function writeSheetFormatPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
301
    {
302
        // sheetFormatPr
303 165
        $objWriter->startElement('sheetFormatPr');
304
305
        // Default row height
306 165
        if ($worksheet->getDefaultRowDimension()->getRowHeight() >= 0) {
307 9
            $objWriter->writeAttribute('customHeight', 'true');
308 9
            $objWriter->writeAttribute('defaultRowHeight', StringHelper::formatNumber($worksheet->getDefaultRowDimension()->getRowHeight()));
309
        } else {
310 156
            $objWriter->writeAttribute('defaultRowHeight', '14.4');
311
        }
312
313
        // Set Zero Height row
314
        if (
315 165
            (string) $worksheet->getDefaultRowDimension()->getZeroHeight() === '1' ||
316 165
            strtolower((string) $worksheet->getDefaultRowDimension()->getZeroHeight()) == 'true'
317
        ) {
318
            $objWriter->writeAttribute('zeroHeight', '1');
319
        }
320
321
        // Default column width
322 165
        if ($worksheet->getDefaultColumnDimension()->getWidth() >= 0) {
323 9
            $objWriter->writeAttribute('defaultColWidth', StringHelper::formatNumber($worksheet->getDefaultColumnDimension()->getWidth()));
324
        }
325
326
        // Outline level - row
327 165
        $outlineLevelRow = 0;
328 165
        foreach ($worksheet->getRowDimensions() as $dimension) {
329 23
            if ($dimension->getOutlineLevel() > $outlineLevelRow) {
330
                $outlineLevelRow = $dimension->getOutlineLevel();
331
            }
332
        }
333 165
        $objWriter->writeAttribute('outlineLevelRow', (int) $outlineLevelRow);
334
335
        // Outline level - column
336 165
        $outlineLevelCol = 0;
337 165
        foreach ($worksheet->getColumnDimensions() as $dimension) {
338 36
            if ($dimension->getOutlineLevel() > $outlineLevelCol) {
339 1
                $outlineLevelCol = $dimension->getOutlineLevel();
340
            }
341
        }
342 165
        $objWriter->writeAttribute('outlineLevelCol', (int) $outlineLevelCol);
343
344 165
        $objWriter->endElement();
345 165
    }
346
347
    /**
348
     * Write Cols.
349
     */
350 165
    private function writeCols(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
351
    {
352
        // cols
353 165
        if (count($worksheet->getColumnDimensions()) > 0) {
354 36
            $objWriter->startElement('cols');
355
356 36
            $worksheet->calculateColumnWidths();
357
358
            // Loop through column dimensions
359 36
            foreach ($worksheet->getColumnDimensions() as $colDimension) {
360
                // col
361 36
                $objWriter->startElement('col');
362 36
                $objWriter->writeAttribute('min', Coordinate::columnIndexFromString($colDimension->getColumnIndex()));
363 36
                $objWriter->writeAttribute('max', Coordinate::columnIndexFromString($colDimension->getColumnIndex()));
364
365 36
                if ($colDimension->getWidth() < 0) {
366
                    // No width set, apply default of 10
367 3
                    $objWriter->writeAttribute('width', '9.10');
368
                } else {
369
                    // Width set
370 35
                    $objWriter->writeAttribute('width', StringHelper::formatNumber($colDimension->getWidth()));
371
                }
372
373
                // Column visibility
374 36
                if ($colDimension->getVisible() === false) {
375 4
                    $objWriter->writeAttribute('hidden', 'true');
376
                }
377
378
                // Auto size?
379 36
                if ($colDimension->getAutoSize()) {
380 14
                    $objWriter->writeAttribute('bestFit', 'true');
381
                }
382
383
                // Custom width?
384 36
                if ($colDimension->getWidth() != $worksheet->getDefaultColumnDimension()->getWidth()) {
385 35
                    $objWriter->writeAttribute('customWidth', 'true');
386
                }
387
388
                // Collapsed
389 36
                if ($colDimension->getCollapsed() === true) {
390 1
                    $objWriter->writeAttribute('collapsed', 'true');
391
                }
392
393
                // Outline level
394 36
                if ($colDimension->getOutlineLevel() > 0) {
395 1
                    $objWriter->writeAttribute('outlineLevel', $colDimension->getOutlineLevel());
396
                }
397
398
                // Style
399 36
                $objWriter->writeAttribute('style', $colDimension->getXfIndex());
400
401 36
                $objWriter->endElement();
402
            }
403
404 36
            $objWriter->endElement();
405
        }
406 165
    }
407
408
    /**
409
     * Write SheetProtection.
410
     */
411 165
    private function writeSheetProtection(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
412
    {
413
        // sheetProtection
414 165
        $objWriter->startElement('sheetProtection');
415
416 165
        $protection = $worksheet->getProtection();
417
418 165
        if ($protection->getAlgorithm()) {
419 1
            $objWriter->writeAttribute('algorithmName', $protection->getAlgorithm());
420 1
            $objWriter->writeAttribute('hashValue', $protection->getPassword());
421 1
            $objWriter->writeAttribute('saltValue', $protection->getSalt());
422 1
            $objWriter->writeAttribute('spinCount', $protection->getSpinCount());
423 164
        } elseif ($protection->getPassword() !== '') {
424 3
            $objWriter->writeAttribute('password', $protection->getPassword());
425
        }
426
427 165
        $objWriter->writeAttribute('sheet', ($protection->getSheet() ? 'true' : 'false'));
428 165
        $objWriter->writeAttribute('objects', ($protection->getObjects() ? 'true' : 'false'));
429 165
        $objWriter->writeAttribute('scenarios', ($protection->getScenarios() ? 'true' : 'false'));
430 165
        $objWriter->writeAttribute('formatCells', ($protection->getFormatCells() ? 'true' : 'false'));
431 165
        $objWriter->writeAttribute('formatColumns', ($protection->getFormatColumns() ? 'true' : 'false'));
432 165
        $objWriter->writeAttribute('formatRows', ($protection->getFormatRows() ? 'true' : 'false'));
433 165
        $objWriter->writeAttribute('insertColumns', ($protection->getInsertColumns() ? 'true' : 'false'));
434 165
        $objWriter->writeAttribute('insertRows', ($protection->getInsertRows() ? 'true' : 'false'));
435 165
        $objWriter->writeAttribute('insertHyperlinks', ($protection->getInsertHyperlinks() ? 'true' : 'false'));
436 165
        $objWriter->writeAttribute('deleteColumns', ($protection->getDeleteColumns() ? 'true' : 'false'));
437 165
        $objWriter->writeAttribute('deleteRows', ($protection->getDeleteRows() ? 'true' : 'false'));
438 165
        $objWriter->writeAttribute('selectLockedCells', ($protection->getSelectLockedCells() ? 'true' : 'false'));
439 165
        $objWriter->writeAttribute('sort', ($protection->getSort() ? 'true' : 'false'));
440 165
        $objWriter->writeAttribute('autoFilter', ($protection->getAutoFilter() ? 'true' : 'false'));
441 165
        $objWriter->writeAttribute('pivotTables', ($protection->getPivotTables() ? 'true' : 'false'));
442 165
        $objWriter->writeAttribute('selectUnlockedCells', ($protection->getSelectUnlockedCells() ? 'true' : 'false'));
443 165
        $objWriter->endElement();
444 165
    }
445
446 157
    private static function writeAttributeIf(XMLWriter $objWriter, $condition, string $attr, string $val): void
447
    {
448 157
        if ($condition) {
449 50
            $objWriter->writeAttribute($attr, $val);
450
        }
451 157
    }
452
453 165
    private static function writeAttributeNotNull(XMLWriter $objWriter, string $attr, ?string $val): void
454
    {
455 165
        if ($val !== null) {
456 8
            $objWriter->writeAttribute($attr, $val);
457
        }
458 165
    }
459
460 112
    private static function writeElementIf(XMLWriter $objWriter, $condition, string $attr, string $val): void
461
    {
462 112
        if ($condition) {
463 112
            $objWriter->writeElement($attr, $val);
464
        }
465 112
    }
466
467 9
    private static function writeOtherCondElements(XMLWriter $objWriter, Conditional $conditional, string $cellCoordinate): void
468
    {
469
        if (
470 9
            $conditional->getConditionType() == Conditional::CONDITION_CELLIS
471 9
            || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
472 9
            || $conditional->getConditionType() == Conditional::CONDITION_EXPRESSION
473
        ) {
474 6
            foreach ($conditional->getConditions() as $formula) {
475
                // Formula
476 6
                $objWriter->writeElement('formula', Xlfn::addXlfn($formula));
477
            }
478 4
        } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSBLANKS) {
479
            // formula copied from ms xlsx xml source file
480 2
            $objWriter->writeElement('formula', 'LEN(TRIM(' . $cellCoordinate . '))=0');
481 3
        } elseif ($conditional->getConditionType() == Conditional::CONDITION_NOTCONTAINSBLANKS) {
482
            // formula copied from ms xlsx xml source file
483 1
            $objWriter->writeElement('formula', 'LEN(TRIM(' . $cellCoordinate . '))>0');
484
        }
485 9
    }
486
487 2
    private static function writeTextCondElements(XMLWriter $objWriter, Conditional $conditional, string $cellCoordinate): void
488
    {
489 2
        $txt = $conditional->getText();
490 2
        if ($txt !== null) {
0 ignored issues
show
introduced by
The condition $txt !== null is always true.
Loading history...
491 2
            $objWriter->writeAttribute('text', $txt);
492 2
            if ($conditional->getOperatorType() == Conditional::OPERATOR_CONTAINSTEXT) {
493 1
                $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $txt . '",' . $cellCoordinate . ')))');
494 2
            } elseif ($conditional->getOperatorType() == Conditional::OPERATOR_BEGINSWITH) {
495 1
                $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($txt) . ')="' . $txt . '"');
496 2
            } elseif ($conditional->getOperatorType() == Conditional::OPERATOR_ENDSWITH) {
497 1
                $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($txt) . ')="' . $txt . '"');
498 2
            } elseif ($conditional->getOperatorType() == Conditional::OPERATOR_NOTCONTAINS) {
499 2
                $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $txt . '",' . $cellCoordinate . '))');
500
            }
501
        }
502 2
    }
503
504 1
    private static function writeExtConditionalFormattingElements(XMLWriter $objWriter, ConditionalFormattingRuleExtension $ruleExtension): void
505
    {
506 1
        $prefix = 'x14';
507 1
        $objWriter->startElementNs($prefix, 'conditionalFormatting', null);
508
509 1
        $objWriter->startElementNs($prefix, 'cfRule', null);
510 1
        $objWriter->writeAttribute('type', $ruleExtension->getCfRule());
511 1
        $objWriter->writeAttribute('id', $ruleExtension->getId());
512 1
        $objWriter->startElementNs($prefix, 'dataBar', null);
513 1
        $dataBar = $ruleExtension->getDataBarExt();
514 1
        foreach ($dataBar->getXmlAttributes() as $attrKey => $val) {
515 1
            $objWriter->writeAttribute($attrKey, $val);
516
        }
517 1
        $minCfvo = $dataBar->getMinimumConditionalFormatValueObject();
518 1
        if ($minCfvo) {
0 ignored issues
show
introduced by
$minCfvo is of type PhpOffice\PhpSpreadsheet...tionalFormatValueObject, thus it always evaluated to true.
Loading history...
519 1
            $objWriter->startElementNs($prefix, 'cfvo', null);
520 1
            $objWriter->writeAttribute('type', $minCfvo->getType());
521 1
            if ($minCfvo->getCellFormula()) {
522 1
                $objWriter->writeElement('xm:f', $minCfvo->getCellFormula());
523
            }
524 1
            $objWriter->endElement(); //end cfvo
525
        }
526
527 1
        $maxCfvo = $dataBar->getMaximumConditionalFormatValueObject();
528 1
        if ($maxCfvo) {
0 ignored issues
show
introduced by
$maxCfvo is of type PhpOffice\PhpSpreadsheet...tionalFormatValueObject, thus it always evaluated to true.
Loading history...
529 1
            $objWriter->startElementNs($prefix, 'cfvo', null);
530 1
            $objWriter->writeAttribute('type', $maxCfvo->getType());
531 1
            if ($maxCfvo->getCellFormula()) {
532 1
                $objWriter->writeElement('xm:f', $maxCfvo->getCellFormula());
533
            }
534 1
            $objWriter->endElement(); //end cfvo
535
        }
536
537 1
        foreach ($dataBar->getXmlElements() as $elmKey => $elmAttr) {
538 1
            $objWriter->startElementNs($prefix, $elmKey, null);
539 1
            foreach ($elmAttr as $attrKey => $attrVal) {
540 1
                $objWriter->writeAttribute($attrKey, $attrVal);
541
            }
542 1
            $objWriter->endElement(); //end elmKey
543
        }
544 1
        $objWriter->endElement(); //end dataBar
545 1
        $objWriter->endElement(); //end cfRule
546 1
        $objWriter->writeElement('xm:sqref', $ruleExtension->getSqref());
547 1
        $objWriter->endElement(); //end conditionalFormatting
548 1
    }
549
550 11
    private static function writeDataBarElements(XMLWriter $objWriter, $dataBar): void
551
    {
552
        /** @var ConditionalDataBar $dataBar */
553 11
        if ($dataBar) {
0 ignored issues
show
introduced by
$dataBar is of type PhpOffice\PhpSpreadsheet...ting\ConditionalDataBar, thus it always evaluated to true.
Loading history...
554 2
            $objWriter->startElement('dataBar');
555 2
            self::writeAttributeIf($objWriter, null !== $dataBar->getShowValue(), 'showValue', $dataBar->getShowValue() ? '1' : '0');
556
557 2
            $minCfvo = $dataBar->getMinimumConditionalFormatValueObject();
558 2
            if ($minCfvo) {
0 ignored issues
show
introduced by
$minCfvo is of type PhpOffice\PhpSpreadsheet...tionalFormatValueObject, thus it always evaluated to true.
Loading history...
559 2
                $objWriter->startElement('cfvo');
560 2
                self::writeAttributeIf($objWriter, $minCfvo->getType(), 'type', (string) $minCfvo->getType());
561 2
                self::writeAttributeIf($objWriter, $minCfvo->getValue(), 'val', (string) $minCfvo->getValue());
562 2
                $objWriter->endElement();
563
            }
564 2
            $maxCfvo = $dataBar->getMaximumConditionalFormatValueObject();
565 2
            if ($maxCfvo) {
0 ignored issues
show
introduced by
$maxCfvo is of type PhpOffice\PhpSpreadsheet...tionalFormatValueObject, thus it always evaluated to true.
Loading history...
566 2
                $objWriter->startElement('cfvo');
567 2
                self::writeAttributeIf($objWriter, $maxCfvo->getType(), 'type', (string) $maxCfvo->getType());
568 2
                self::writeAttributeIf($objWriter, $maxCfvo->getValue(), 'val', (string) $maxCfvo->getValue());
569 2
                $objWriter->endElement();
570
            }
571 2
            if ($dataBar->getColor()) {
572 2
                $objWriter->startElement('color');
573 2
                $objWriter->writeAttribute('rgb', $dataBar->getColor());
574 2
                $objWriter->endElement();
575
            }
576 2
            $objWriter->endElement(); // end dataBar
577
578 2
            if ($dataBar->getConditionalFormattingRuleExt()) {
579 1
                $objWriter->startElement('extLst');
580 1
                $extension = $dataBar->getConditionalFormattingRuleExt();
581 1
                $objWriter->startElement('ext');
582 1
                $objWriter->writeAttribute('uri', '{B025F937-C7B1-47D3-B67F-A62EFF666E3E}');
583 1
                $objWriter->startElementNs('x14', 'id', null);
584 1
                $objWriter->text($extension->getId());
585 1
                $objWriter->endElement();
586 1
                $objWriter->endElement();
587 1
                $objWriter->endElement(); //end extLst
588
            }
589
        }
590 11
    }
591
592
    /**
593
     * Write ConditionalFormatting.
594
     */
595 165
    private function writeConditionalFormatting(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
596
    {
597
        // Conditional id
598 165
        $id = 1;
599
600
        // Loop through styles in the current worksheet
601 165
        foreach ($worksheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
602 11
            foreach ($conditionalStyles as $conditional) {
603
                // WHY was this again?
604
                // if ($this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) == '') {
605
                //    continue;
606
                // }
607 11
                if ($conditional->getConditionType() != Conditional::CONDITION_NONE) {
608
                    // conditionalFormatting
609 11
                    $objWriter->startElement('conditionalFormatting');
610 11
                    $objWriter->writeAttribute('sqref', $cellCoordinate);
611
612
                    // cfRule
613 11
                    $objWriter->startElement('cfRule');
614 11
                    $objWriter->writeAttribute('type', $conditional->getConditionType());
615 11
                    self::writeAttributeIf(
616 11
                        $objWriter,
617 11
                        ($conditional->getConditionType() != Conditional::CONDITION_DATABAR),
618
                        'dxfId',
619 11
                        (string) $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode())
620
                    );
621 11
                    $objWriter->writeAttribute('priority', $id++);
622
623 11
                    self::writeAttributeif(
624 11
                        $objWriter,
625
                        (
626 11
                            $conditional->getConditionType() === Conditional::CONDITION_CELLIS
627 11
                            || $conditional->getConditionType() === Conditional::CONDITION_CONTAINSTEXT
628 11
                            || $conditional->getConditionType() === Conditional::CONDITION_NOTCONTAINSTEXT
629 7
                        ) && $conditional->getOperatorType() !== Conditional::OPERATOR_NONE,
630
                        'operator',
631 11
                        $conditional->getOperatorType()
632
                    );
633
634 11
                    self::writeAttributeIf($objWriter, $conditional->getStopIfTrue(), 'stopIfTrue', '1');
635
636
                    if (
637 11
                        $conditional->getConditionType() === Conditional::CONDITION_CONTAINSTEXT
638 11
                        || $conditional->getConditionType() === Conditional::CONDITION_NOTCONTAINSTEXT
639
                    ) {
640 2
                        self::writeTextCondElements($objWriter, $conditional, $cellCoordinate);
641
                    } else {
642 9
                        self::writeOtherCondElements($objWriter, $conditional, $cellCoordinate);
643
                    }
644
645
                    //<dataBar>
646 11
                    self::writeDataBarElements($objWriter, $conditional->getDataBar());
647
648 11
                    $objWriter->endElement(); //end cfRule
649
650 11
                    $objWriter->endElement();
651
                }
652
            }
653
        }
654 165
    }
655
656
    /**
657
     * Write DataValidations.
658
     */
659 165
    private function writeDataValidations(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
660
    {
661
        // Datavalidation collection
662 165
        $dataValidationCollection = $worksheet->getDataValidationCollection();
663
664
        // Write data validations?
665 165
        if (!empty($dataValidationCollection)) {
666 5
            $dataValidationCollection = Coordinate::mergeRangesInCollection($dataValidationCollection);
667 5
            $objWriter->startElement('dataValidations');
668 5
            $objWriter->writeAttribute('count', count($dataValidationCollection));
669
670 5
            foreach ($dataValidationCollection as $coordinate => $dv) {
671 5
                $objWriter->startElement('dataValidation');
672
673 5
                if ($dv->getType() != '') {
674 5
                    $objWriter->writeAttribute('type', $dv->getType());
675
                }
676
677 5
                if ($dv->getErrorStyle() != '') {
678 3
                    $objWriter->writeAttribute('errorStyle', $dv->getErrorStyle());
679
                }
680
681 5
                if ($dv->getOperator() != '') {
682 3
                    $objWriter->writeAttribute('operator', $dv->getOperator());
683
                }
684
685 5
                $objWriter->writeAttribute('allowBlank', ($dv->getAllowBlank() ? '1' : '0'));
686 5
                $objWriter->writeAttribute('showDropDown', (!$dv->getShowDropDown() ? '1' : '0'));
687 5
                $objWriter->writeAttribute('showInputMessage', ($dv->getShowInputMessage() ? '1' : '0'));
688 5
                $objWriter->writeAttribute('showErrorMessage', ($dv->getShowErrorMessage() ? '1' : '0'));
689
690 5
                if ($dv->getErrorTitle() !== '') {
691 3
                    $objWriter->writeAttribute('errorTitle', $dv->getErrorTitle());
692
                }
693 5
                if ($dv->getError() !== '') {
694 3
                    $objWriter->writeAttribute('error', $dv->getError());
695
                }
696 5
                if ($dv->getPromptTitle() !== '') {
697 4
                    $objWriter->writeAttribute('promptTitle', $dv->getPromptTitle());
698
                }
699 5
                if ($dv->getPrompt() !== '') {
700 3
                    $objWriter->writeAttribute('prompt', $dv->getPrompt());
701
                }
702
703 5
                $objWriter->writeAttribute('sqref', $dv->getSqref() ?? $coordinate);
704
705 5
                if ($dv->getFormula1() !== '') {
706 5
                    $objWriter->writeElement('formula1', $dv->getFormula1());
707
                }
708 5
                if ($dv->getFormula2() !== '') {
709 1
                    $objWriter->writeElement('formula2', $dv->getFormula2());
710
                }
711
712 5
                $objWriter->endElement();
713
            }
714
715 5
            $objWriter->endElement();
716
        }
717 165
    }
718
719
    /**
720
     * Write Hyperlinks.
721
     */
722 165
    private function writeHyperlinks(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
723
    {
724
        // Hyperlink collection
725 165
        $hyperlinkCollection = $worksheet->getHyperlinkCollection();
726
727
        // Relation ID
728 165
        $relationId = 1;
729
730
        // Write hyperlinks?
731 165
        if (!empty($hyperlinkCollection)) {
732 11
            $objWriter->startElement('hyperlinks');
733
734 11
            foreach ($hyperlinkCollection as $coordinate => $hyperlink) {
735 11
                $objWriter->startElement('hyperlink');
736
737 11
                $objWriter->writeAttribute('ref', $coordinate);
738 11
                if (!$hyperlink->isInternal()) {
739 11
                    $objWriter->writeAttribute('r:id', 'rId_hyperlink_' . $relationId);
740 11
                    ++$relationId;
741
                } else {
742 7
                    $objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl()));
743
                }
744
745 11
                if ($hyperlink->getTooltip() !== '') {
746 7
                    $objWriter->writeAttribute('tooltip', $hyperlink->getTooltip());
747 7
                    $objWriter->writeAttribute('display', $hyperlink->getTooltip());
748
                }
749
750 11
                $objWriter->endElement();
751
            }
752
753 11
            $objWriter->endElement();
754
        }
755 165
    }
756
757
    /**
758
     * Write ProtectedRanges.
759
     */
760 165
    private function writeProtectedRanges(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
761
    {
762 165
        if (count($worksheet->getProtectedCells()) > 0) {
763
            // protectedRanges
764 6
            $objWriter->startElement('protectedRanges');
765
766
            // Loop protectedRanges
767 6
            foreach ($worksheet->getProtectedCells() as $protectedCell => $passwordHash) {
768
                // protectedRange
769 6
                $objWriter->startElement('protectedRange');
770 6
                $objWriter->writeAttribute('name', 'p' . md5($protectedCell));
771 6
                $objWriter->writeAttribute('sqref', $protectedCell);
772 6
                if (!empty($passwordHash)) {
773 6
                    $objWriter->writeAttribute('password', $passwordHash);
774
                }
775 6
                $objWriter->endElement();
776
            }
777
778 6
            $objWriter->endElement();
779
        }
780 165
    }
781
782
    /**
783
     * Write MergeCells.
784
     */
785 165
    private function writeMergeCells(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
786
    {
787 165
        if (count($worksheet->getMergeCells()) > 0) {
788
            // mergeCells
789 14
            $objWriter->startElement('mergeCells');
790
791
            // Loop mergeCells
792 14
            foreach ($worksheet->getMergeCells() as $mergeCell) {
793
                // mergeCell
794 14
                $objWriter->startElement('mergeCell');
795 14
                $objWriter->writeAttribute('ref', $mergeCell);
796 14
                $objWriter->endElement();
797
            }
798
799 14
            $objWriter->endElement();
800
        }
801 165
    }
802
803
    /**
804
     * Write PrintOptions.
805
     */
806 165
    private function writePrintOptions(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
807
    {
808
        // printOptions
809 165
        $objWriter->startElement('printOptions');
810
811 165
        $objWriter->writeAttribute('gridLines', ($worksheet->getPrintGridlines() ? 'true' : 'false'));
812 165
        $objWriter->writeAttribute('gridLinesSet', 'true');
813
814 165
        if ($worksheet->getPageSetup()->getHorizontalCentered()) {
815
            $objWriter->writeAttribute('horizontalCentered', 'true');
816
        }
817
818 165
        if ($worksheet->getPageSetup()->getVerticalCentered()) {
819
            $objWriter->writeAttribute('verticalCentered', 'true');
820
        }
821
822 165
        $objWriter->endElement();
823 165
    }
824
825
    /**
826
     * Write PageMargins.
827
     */
828 165
    private function writePageMargins(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
829
    {
830
        // pageMargins
831 165
        $objWriter->startElement('pageMargins');
832 165
        $objWriter->writeAttribute('left', StringHelper::formatNumber($worksheet->getPageMargins()->getLeft()));
833 165
        $objWriter->writeAttribute('right', StringHelper::formatNumber($worksheet->getPageMargins()->getRight()));
834 165
        $objWriter->writeAttribute('top', StringHelper::formatNumber($worksheet->getPageMargins()->getTop()));
835 165
        $objWriter->writeAttribute('bottom', StringHelper::formatNumber($worksheet->getPageMargins()->getBottom()));
836 165
        $objWriter->writeAttribute('header', StringHelper::formatNumber($worksheet->getPageMargins()->getHeader()));
837 165
        $objWriter->writeAttribute('footer', StringHelper::formatNumber($worksheet->getPageMargins()->getFooter()));
838 165
        $objWriter->endElement();
839 165
    }
840
841
    /**
842
     * Write AutoFilter.
843
     */
844 165
    private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
845
    {
846 165
        $autoFilterRange = $worksheet->getAutoFilter()->getRange();
847 165
        if (!empty($autoFilterRange)) {
848
            // autoFilter
849 4
            $objWriter->startElement('autoFilter');
850
851
            // Strip any worksheet reference from the filter coordinates
852 4
            $range = Coordinate::splitRange($autoFilterRange);
853 4
            $range = $range[0];
854
            //    Strip any worksheet ref
855 4
            [$ws, $range[0]] = PhpspreadsheetWorksheet::extractSheetTitle($range[0], true);
856 4
            $range = implode(':', $range);
857
858 4
            $objWriter->writeAttribute('ref', str_replace('$', '', $range));
859
860 4
            $columns = $worksheet->getAutoFilter()->getColumns();
861 4
            if (count($columns) > 0) {
862 3
                foreach ($columns as $columnID => $column) {
863 3
                    $rules = $column->getRules();
864 3
                    if (count($rules) > 0) {
865 3
                        $objWriter->startElement('filterColumn');
866 3
                        $objWriter->writeAttribute('colId', $worksheet->getAutoFilter()->getColumnOffset($columnID));
867
868 3
                        $objWriter->startElement($column->getFilterType());
869 3
                        if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) {
870 1
                            $objWriter->writeAttribute('and', 1);
871
                        }
872
873 3
                        foreach ($rules as $rule) {
874
                            if (
875 3
                                ($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) &&
876 3
                                ($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) &&
877 3
                                ($rule->getValue() === '')
878
                            ) {
879
                                //    Filter rule for Blanks
880 1
                                $objWriter->writeAttribute('blank', 1);
881 3
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) {
882
                                //    Dynamic Filter Rule
883 2
                                $objWriter->writeAttribute('type', $rule->getGrouping());
884 2
                                $val = $column->getAttribute('val');
885 2
                                if ($val !== null) {
886 2
                                    $objWriter->writeAttribute('val', "$val");
887
                                }
888 2
                                $maxVal = $column->getAttribute('maxVal');
889 2
                                if ($maxVal !== null) {
890 2
                                    $objWriter->writeAttribute('maxVal', "$maxVal");
891
                                }
892 2
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) {
893
                                //    Top 10 Filter Rule
894
                                $ruleValue = $rule->getValue();
895
                                if (!is_array($ruleValue)) {
896
                                    $objWriter->writeAttribute('val', "$ruleValue");
897
                                }
898
                                $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0'));
899
                                $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0'));
900
                            } else {
901
                                //    Filter, DateGroupItem or CustomFilter
902 2
                                $objWriter->startElement($rule->getRuleType());
903
904 2
                                if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) {
905 1
                                    $objWriter->writeAttribute('operator', $rule->getOperator());
906
                                }
907 2
                                if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) {
908
                                    // Date Group filters
909 1
                                    $ruleValue = $rule->getValue();
910 1
                                    if (is_array($ruleValue)) {
911 1
                                        foreach ($ruleValue as $key => $value) {
912 1
                                            $objWriter->writeAttribute($key, "$value");
913
                                        }
914
                                    }
915 1
                                    $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping());
916
                                } else {
917 2
                                    $ruleValue = $rule->getValue();
918 2
                                    if (!is_array($ruleValue)) {
919 2
                                        $objWriter->writeAttribute('val', "$ruleValue");
920
                                    }
921
                                }
922
923 2
                                $objWriter->endElement();
924
                            }
925
                        }
926
927 3
                        $objWriter->endElement();
928
929 3
                        $objWriter->endElement();
930
                    }
931
                }
932
            }
933 4
            $objWriter->endElement();
934
        }
935 165
    }
936
937
    /**
938
     * Write PageSetup.
939
     */
940 165
    private function writePageSetup(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
941
    {
942
        // pageSetup
943 165
        $objWriter->startElement('pageSetup');
944 165
        $objWriter->writeAttribute('paperSize', $worksheet->getPageSetup()->getPaperSize());
945 165
        $objWriter->writeAttribute('orientation', $worksheet->getPageSetup()->getOrientation());
946
947 165
        if ($worksheet->getPageSetup()->getScale() !== null) {
948 165
            $objWriter->writeAttribute('scale', $worksheet->getPageSetup()->getScale());
949
        }
950 165
        if ($worksheet->getPageSetup()->getFitToHeight() !== null) {
951 165
            $objWriter->writeAttribute('fitToHeight', $worksheet->getPageSetup()->getFitToHeight());
952
        } else {
953
            $objWriter->writeAttribute('fitToHeight', '0');
954
        }
955 165
        if ($worksheet->getPageSetup()->getFitToWidth() !== null) {
956 165
            $objWriter->writeAttribute('fitToWidth', $worksheet->getPageSetup()->getFitToWidth());
957
        } else {
958
            $objWriter->writeAttribute('fitToWidth', '0');
959
        }
960 165
        if ($worksheet->getPageSetup()->getFirstPageNumber() !== null) {
0 ignored issues
show
introduced by
The condition $worksheet->getPageSetup...stPageNumber() !== null is always true.
Loading history...
961
            $objWriter->writeAttribute('firstPageNumber', $worksheet->getPageSetup()->getFirstPageNumber());
962
            $objWriter->writeAttribute('useFirstPageNumber', '1');
963
        }
964 165
        $objWriter->writeAttribute('pageOrder', $worksheet->getPageSetup()->getPageOrder());
965
966 165
        $getUnparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
967 165
        if (isset($getUnparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId'])) {
968 8
            $objWriter->writeAttribute('r:id', $getUnparsedLoadedData['sheets'][$worksheet->getCodeName()]['pageSetupRelId']);
969
        }
970
971 165
        $objWriter->endElement();
972 165
    }
973
974
    /**
975
     * Write Header / Footer.
976
     */
977 165
    private function writeHeaderFooter(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
978
    {
979
        // headerFooter
980 165
        $objWriter->startElement('headerFooter');
981 165
        $objWriter->writeAttribute('differentOddEven', ($worksheet->getHeaderFooter()->getDifferentOddEven() ? 'true' : 'false'));
982 165
        $objWriter->writeAttribute('differentFirst', ($worksheet->getHeaderFooter()->getDifferentFirst() ? 'true' : 'false'));
983 165
        $objWriter->writeAttribute('scaleWithDoc', ($worksheet->getHeaderFooter()->getScaleWithDocument() ? 'true' : 'false'));
984 165
        $objWriter->writeAttribute('alignWithMargins', ($worksheet->getHeaderFooter()->getAlignWithMargins() ? 'true' : 'false'));
985
986 165
        $objWriter->writeElement('oddHeader', $worksheet->getHeaderFooter()->getOddHeader());
987 165
        $objWriter->writeElement('oddFooter', $worksheet->getHeaderFooter()->getOddFooter());
988 165
        $objWriter->writeElement('evenHeader', $worksheet->getHeaderFooter()->getEvenHeader());
989 165
        $objWriter->writeElement('evenFooter', $worksheet->getHeaderFooter()->getEvenFooter());
990 165
        $objWriter->writeElement('firstHeader', $worksheet->getHeaderFooter()->getFirstHeader());
991 165
        $objWriter->writeElement('firstFooter', $worksheet->getHeaderFooter()->getFirstFooter());
992 165
        $objWriter->endElement();
993 165
    }
994
995
    /**
996
     * Write Breaks.
997
     */
998 165
    private function writeBreaks(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
999
    {
1000
        // Get row and column breaks
1001 165
        $aRowBreaks = [];
1002 165
        $aColumnBreaks = [];
1003 165
        foreach ($worksheet->getBreaks() as $cell => $breakType) {
1004 1
            if ($breakType == PhpspreadsheetWorksheet::BREAK_ROW) {
1005 1
                $aRowBreaks[] = $cell;
1006
            } elseif ($breakType == PhpspreadsheetWorksheet::BREAK_COLUMN) {
1007
                $aColumnBreaks[] = $cell;
1008
            }
1009
        }
1010
1011
        // rowBreaks
1012 165
        if (!empty($aRowBreaks)) {
1013 1
            $objWriter->startElement('rowBreaks');
1014 1
            $objWriter->writeAttribute('count', count($aRowBreaks));
1015 1
            $objWriter->writeAttribute('manualBreakCount', count($aRowBreaks));
1016
1017 1
            foreach ($aRowBreaks as $cell) {
1018 1
                $coords = Coordinate::coordinateFromString($cell);
1019
1020 1
                $objWriter->startElement('brk');
1021 1
                $objWriter->writeAttribute('id', $coords[1]);
1022 1
                $objWriter->writeAttribute('man', '1');
1023 1
                $objWriter->endElement();
1024
            }
1025
1026 1
            $objWriter->endElement();
1027
        }
1028
1029
        // Second, write column breaks
1030 165
        if (!empty($aColumnBreaks)) {
1031
            $objWriter->startElement('colBreaks');
1032
            $objWriter->writeAttribute('count', count($aColumnBreaks));
1033
            $objWriter->writeAttribute('manualBreakCount', count($aColumnBreaks));
1034
1035
            foreach ($aColumnBreaks as $cell) {
1036
                $coords = Coordinate::coordinateFromString($cell);
1037
1038
                $objWriter->startElement('brk');
1039
                $objWriter->writeAttribute('id', Coordinate::columnIndexFromString($coords[0]) - 1);
1040
                $objWriter->writeAttribute('man', '1');
1041
                $objWriter->endElement();
1042
            }
1043
1044
            $objWriter->endElement();
1045
        }
1046 165
    }
1047
1048
    /**
1049
     * Write SheetData.
1050
     *
1051
     * @param string[] $stringTable String table
1052
     */
1053 165
    private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet, array $stringTable): void
1054
    {
1055
        // Flipped stringtable, for faster index searching
1056 165
        $aFlippedStringTable = $this->getParentWriter()->getWriterPartstringtable()->flipStringTable($stringTable);
1057
1058
        // sheetData
1059 165
        $objWriter->startElement('sheetData');
1060
1061
        // Get column count
1062 165
        $colCount = Coordinate::columnIndexFromString($worksheet->getHighestColumn());
1063
1064
        // Highest row number
1065 165
        $highestRow = $worksheet->getHighestRow();
1066
1067
        // Loop through cells
1068 165
        $cellsByRow = [];
1069 165
        foreach ($worksheet->getCoordinates() as $coordinate) {
1070 156
            $cellAddress = Coordinate::coordinateFromString($coordinate);
1071 156
            $cellsByRow[$cellAddress[1]][] = $coordinate;
1072
        }
1073
1074 165
        $currentRow = 0;
1075 165
        while ($currentRow++ < $highestRow) {
1076
            // Get row dimension
1077 165
            $rowDimension = $worksheet->getRowDimension($currentRow);
1078
1079
            // Write current row?
1080 165
            $writeCurrentRow = isset($cellsByRow[$currentRow]) || $rowDimension->getRowHeight() >= 0 || $rowDimension->getVisible() == false || $rowDimension->getCollapsed() == true || $rowDimension->getOutlineLevel() > 0 || $rowDimension->getXfIndex() !== null;
0 ignored issues
show
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...
1081
1082 165
            if ($writeCurrentRow) {
1083
                // Start a new row
1084 156
                $objWriter->startElement('row');
1085 156
                $objWriter->writeAttribute('r', $currentRow);
1086 156
                $objWriter->writeAttribute('spans', '1:' . $colCount);
1087
1088
                // Row dimensions
1089 156
                if ($rowDimension->getRowHeight() >= 0) {
1090 12
                    $objWriter->writeAttribute('customHeight', '1');
1091 12
                    $objWriter->writeAttribute('ht', StringHelper::formatNumber($rowDimension->getRowHeight()));
1092
                }
1093
1094
                // Row visibility
1095 156
                if (!$rowDimension->getVisible() === true) {
1096 5
                    $objWriter->writeAttribute('hidden', 'true');
1097
                }
1098
1099
                // Collapsed
1100 156
                if ($rowDimension->getCollapsed() === true) {
1101
                    $objWriter->writeAttribute('collapsed', 'true');
1102
                }
1103
1104
                // Outline level
1105 156
                if ($rowDimension->getOutlineLevel() > 0) {
1106
                    $objWriter->writeAttribute('outlineLevel', $rowDimension->getOutlineLevel());
1107
                }
1108
1109
                // Style
1110 156
                if ($rowDimension->getXfIndex() !== null) {
1111
                    $objWriter->writeAttribute('s', $rowDimension->getXfIndex());
1112
                    $objWriter->writeAttribute('customFormat', '1');
1113
                }
1114
1115
                // Write cells
1116 156
                if (isset($cellsByRow[$currentRow])) {
1117 156
                    foreach ($cellsByRow[$currentRow] as $cellAddress) {
1118
                        // Write cell
1119 156
                        $this->writeCell($objWriter, $worksheet, $cellAddress, $aFlippedStringTable);
1120
                    }
1121
                }
1122
1123
                // End row
1124 156
                $objWriter->endElement();
1125
            }
1126
        }
1127
1128 165
        $objWriter->endElement();
1129 165
    }
1130
1131
    /**
1132
     * @param RichText|string $cellValue
1133
     */
1134 8
    private function writeCellInlineStr(XMLWriter $objWriter, string $mappedType, $cellValue): void
1135
    {
1136 8
        $objWriter->writeAttribute('t', $mappedType);
1137 8
        if (!$cellValue instanceof RichText) {
1138
            $objWriter->writeElement(
1139
                't',
1140
                StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue, Settings::htmlEntityFlags()))
1141
            );
1142 8
        } elseif ($cellValue instanceof RichText) {
0 ignored issues
show
introduced by
$cellValue is always a sub-type of PhpOffice\PhpSpreadsheet\RichText\RichText.
Loading history...
1143 8
            $objWriter->startElement('is');
1144 8
            $this->getParentWriter()->getWriterPartstringtable()->writeRichText($objWriter, $cellValue);
1145 8
            $objWriter->endElement();
1146
        }
1147 8
    }
1148
1149
    /**
1150
     * @param RichText|string $cellValue
1151
     * @param string[] $flippedStringTable
1152
     */
1153 107
    private function writeCellString(XMLWriter $objWriter, string $mappedType, $cellValue, array $flippedStringTable): void
1154
    {
1155 107
        $objWriter->writeAttribute('t', $mappedType);
1156 107
        if (!$cellValue instanceof RichText) {
1157 107
            self::writeElementIf($objWriter, isset($flippedStringTable[$cellValue]), 'v', $flippedStringTable[$cellValue] ?? '');
1158
        } else {
1159 2
            $objWriter->writeElement('v', $flippedStringTable[$cellValue->getHashCode()]);
1160
        }
1161 107
    }
1162
1163
    /**
1164
     * @param float|int $cellValue
1165
     */
1166 94
    private function writeCellNumeric(XMLWriter $objWriter, $cellValue): void
1167
    {
1168
        //force a decimal to be written if the type is float
1169 94
        if (is_float($cellValue)) {
1170
            // force point as decimal separator in case current locale uses comma
1171 41
            $cellValue = str_replace(',', '.', (string) $cellValue);
1172 41
            if (strpos($cellValue, '.') === false) {
1173 26
                $cellValue = $cellValue . '.0';
1174
            }
1175
        }
1176 94
        $objWriter->writeElement('v', $cellValue);
1177 94
    }
1178
1179 9
    private function writeCellBoolean(XMLWriter $objWriter, string $mappedType, bool $cellValue): void
1180
    {
1181 9
        $objWriter->writeAttribute('t', $mappedType);
1182 9
        $objWriter->writeElement('v', $cellValue ? '1' : '0');
1183 9
    }
1184
1185 7
    private function writeCellError(XMLWriter $objWriter, string $mappedType, string $cellValue, string $formulaerr = '#NULL!'): void
1186
    {
1187 7
        $objWriter->writeAttribute('t', $mappedType);
1188 7
        $cellIsFormula = substr($cellValue, 0, 1) === '=';
1189 7
        self::writeElementIf($objWriter, $cellIsFormula, 'f', Xlfn::addXlfnStripEquals($cellValue));
1190 7
        $objWriter->writeElement('v', $cellIsFormula ? $formulaerr : $cellValue);
1191 7
    }
1192
1193 43
    private function writeCellFormula(XMLWriter $objWriter, string $cellValue, Cell $cell): void
1194
    {
1195 43
        $calculatedValue = $this->getParentWriter()->getPreCalculateFormulas() ? $cell->getCalculatedValue() : $cellValue;
1196 43
        if (is_string($calculatedValue)) {
1197 21
            if (\PhpOffice\PhpSpreadsheet\Calculation\Functions::isError($calculatedValue)) {
1198 6
                $this->writeCellError($objWriter, 'e', $cellValue, $calculatedValue);
1199
1200 6
                return;
1201
            }
1202 21
            $objWriter->writeAttribute('t', 'str');
1203 21
            $calculatedValue = StringHelper::controlCharacterPHP2OOXML($calculatedValue);
1204 36
        } elseif (is_bool($calculatedValue)) {
1205 6
            $objWriter->writeAttribute('t', 'b');
1206 6
            $calculatedValue = (int) $calculatedValue;
1207
        }
1208
1209 43
        $attributes = $cell->getFormulaAttributes();
1210 43
        if (($attributes['t'] ?? null) === 'array') {
1211
            $objWriter->startElement('f');
1212
            $objWriter->writeAttribute('t', 'array');
1213
            $objWriter->writeAttribute('ref', $cell->getCoordinate());
1214
            $objWriter->writeAttribute('aca', '1');
1215
            $objWriter->writeAttribute('ca', '1');
1216
            $objWriter->text(substr($cellValue, 1));
1217
            $objWriter->endElement();
1218
        } else {
1219 43
            $objWriter->writeElement('f', Xlfn::addXlfnStripEquals($cellValue));
1220 43
            self::writeElementIf(
1221 43
                $objWriter,
1222 43
                $this->getParentWriter()->getOffice2003Compatibility() === false,
1223
                'v',
1224 43
                ($this->getParentWriter()->getPreCalculateFormulas() && !is_array($calculatedValue) && substr($calculatedValue, 0, 1) !== '#')
1225 43
                    ? StringHelper::formatNumber($calculatedValue) : '0'
1226
            );
1227
        }
1228 43
    }
1229
1230
    /**
1231
     * Write Cell.
1232
     *
1233
     * @param string $cellAddress Cell Address
1234
     * @param string[] $flippedStringTable String table (flipped), for faster index searching
1235
     */
1236 156
    private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet, string $cellAddress, array $flippedStringTable): void
1237
    {
1238
        // Cell
1239 156
        $pCell = $worksheet->getCell($cellAddress);
1240 156
        $objWriter->startElement('c');
1241 156
        $objWriter->writeAttribute('r', $cellAddress);
1242
1243
        // Sheet styles
1244 156
        $xfi = $pCell->getXfIndex();
1245 156
        self::writeAttributeIf($objWriter, $xfi, 's', $xfi);
1246
1247
        // If cell value is supplied, write cell value
1248 156
        $cellValue = $pCell->getValue();
1249 156
        if (is_object($cellValue) || $cellValue !== '') {
1250
            // Map type
1251 156
            $mappedType = $pCell->getDataType();
1252
1253
            // Write data depending on its type
1254 156
            switch (strtolower($mappedType)) {
1255 156
                case 'inlinestr':    // Inline string
1256 8
                    $this->writeCellInlineStr($objWriter, $mappedType, $cellValue);
1257
1258 8
                    break;
1259 155
                case 's':            // String
1260 107
                    $this->writeCellString($objWriter, $mappedType, $cellValue, $flippedStringTable);
1261
1262 107
                    break;
1263 124
                case 'f':            // Formula
1264 43
                    $this->writeCellFormula($objWriter, $cellValue, $pCell);
1265
1266 43
                    break;
1267 111
                case 'n':            // Numeric
1268 94
                    $this->writeCellNumeric($objWriter, $cellValue);
1269
1270 94
                    break;
1271 38
                case 'b':            // Boolean
1272 9
                    $this->writeCellBoolean($objWriter, $mappedType, $cellValue);
1273
1274 9
                    break;
1275 33
                case 'e':            // Error
1276 1
                    $this->writeCellError($objWriter, $mappedType, $cellValue);
1277
            }
1278
        }
1279
1280 156
        $objWriter->endElement();
1281 156
    }
1282
1283
    /**
1284
     * Write Drawings.
1285
     *
1286
     * @param bool $includeCharts Flag indicating if we should include drawing details for charts
1287
     */
1288 165
    private function writeDrawings(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet, $includeCharts = false): void
1289
    {
1290 165
        $unparsedLoadedData = $worksheet->getParent()->getUnparsedLoadedData();
1291 165
        $hasUnparsedDrawing = isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds']);
1292 165
        $chartCount = ($includeCharts) ? $worksheet->getChartCollection()->count() : 0;
1293 165
        if ($chartCount == 0 && $worksheet->getDrawingCollection()->count() == 0 && !$hasUnparsedDrawing) {
1294 135
            return;
1295
        }
1296
1297
        // If sheet contains drawings, add the relationships
1298 35
        $objWriter->startElement('drawing');
1299
1300 35
        $rId = 'rId1';
1301 35
        if (isset($unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'])) {
1302 10
            $drawingOriginalIds = $unparsedLoadedData['sheets'][$worksheet->getCodeName()]['drawingOriginalIds'];
1303
            // take first. In future can be overriten
1304
            // (! synchronize with \PhpOffice\PhpSpreadsheet\Writer\Xlsx\Rels::writeWorksheetRelationships)
1305 10
            $rId = reset($drawingOriginalIds);
1306
        }
1307
1308 35
        $objWriter->writeAttribute('r:id', $rId);
1309 35
        $objWriter->endElement();
1310 35
    }
1311
1312
    /**
1313
     * Write LegacyDrawing.
1314
     */
1315 165
    private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
1316
    {
1317
        // If sheet contains comments, add the relationships
1318 165
        if (count($worksheet->getComments()) > 0) {
1319 11
            $objWriter->startElement('legacyDrawing');
1320 11
            $objWriter->writeAttribute('r:id', 'rId_comments_vml1');
1321 11
            $objWriter->endElement();
1322
        }
1323 165
    }
1324
1325
    /**
1326
     * Write LegacyDrawingHF.
1327
     */
1328 165
    private function writeLegacyDrawingHF(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
1329
    {
1330
        // If sheet contains images, add the relationships
1331 165
        if (count($worksheet->getHeaderFooter()->getImages()) > 0) {
1332 1
            $objWriter->startElement('legacyDrawingHF');
1333 1
            $objWriter->writeAttribute('r:id', 'rId_headerfooter_vml1');
1334 1
            $objWriter->endElement();
1335
        }
1336 165
    }
1337
1338 165
    private function writeAlternateContent(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
1339
    {
1340 165
        if (empty($worksheet->getParent()->getUnparsedLoadedData()['sheets'][$worksheet->getCodeName()]['AlternateContents'])) {
1341 165
            return;
1342
        }
1343
1344 1
        foreach ($worksheet->getParent()->getUnparsedLoadedData()['sheets'][$worksheet->getCodeName()]['AlternateContents'] as $alternateContent) {
1345 1
            $objWriter->writeRaw($alternateContent);
1346
        }
1347 1
    }
1348
1349
    /**
1350
     * write <ExtLst>
1351
     * only implementation conditionalFormattings.
1352
     *
1353
     * @url https://docs.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/07d607af-5618-4ca2-b683-6a78dc0d9627
1354
     */
1355 165
    private function writeExtLst(XMLWriter $objWriter, PhpspreadsheetWorksheet $worksheet): void
1356
    {
1357 165
        $conditionalFormattingRuleExtList = [];
1358 165
        foreach ($worksheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
1359
            /** @var Conditional $conditional */
1360 11
            foreach ($conditionalStyles as $conditional) {
1361 11
                $dataBar = $conditional->getDataBar();
1362
                // @phpstan-ignore-next-line
1363 11
                if ($dataBar && $dataBar->getConditionalFormattingRuleExt()) {
1364 1
                    $conditionalFormattingRuleExtList[] = $dataBar->getConditionalFormattingRuleExt();
1365
                }
1366
            }
1367
        }
1368
1369 165
        if (count($conditionalFormattingRuleExtList) > 0) {
1370 1
            $conditionalFormattingRuleExtNsPrefix = 'x14';
1371 1
            $objWriter->startElement('extLst');
1372 1
            $objWriter->startElement('ext');
1373 1
            $objWriter->writeAttribute('uri', '{78C0D931-6437-407d-A8EE-F0AAD7539E65}');
1374 1
            $objWriter->startElementNs($conditionalFormattingRuleExtNsPrefix, 'conditionalFormattings', null);
1375 1
            foreach ($conditionalFormattingRuleExtList as $extension) {
1376 1
                self::writeExtConditionalFormattingElements($objWriter, $extension);
1377
            }
1378 1
            $objWriter->endElement(); //end conditionalFormattings
1379 1
            $objWriter->endElement(); //end ext
1380 1
            $objWriter->endElement(); //end extLst
1381
        }
1382 165
    }
1383
}
1384