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

Worksheet::writeLegacyDrawing()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 2
rs 10
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\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