Failed Conditions
Push — master ( 7635b3...69fc93 )
by Adrien
36s queued 21s
created

Worksheet::writeTextCondElements()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 13
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 11
nc 6
nop 3
dl 0
loc 13
ccs 12
cts 12
cp 1
crap 6
rs 9.2222
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[] $pStringTable
25
     * @param bool $includeCharts Flag indicating if we should write charts
26
     *
27
     * @return string XML Output
28
     */
29 159
    public function writeWorksheet(PhpspreadsheetWorksheet $worksheet, $pStringTable = null, $includeCharts = false)
30
    {
31
        // Create XML writer
32 159
        $objWriter = null;
33 159
        if ($this->getParentWriter()->getUseDiskCaching()) {
34
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
35
        } else {
36 159
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
37
        }
38
39
        // XML header
40 159
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
41
42
        // Worksheet
43 159
        $objWriter->startElement('worksheet');
44 159
        $objWriter->writeAttribute('xml:space', 'preserve');
45 159
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
46 159
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
47
48 159
        $objWriter->writeAttribute('xmlns:xdr', 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing');
49 159
        $objWriter->writeAttribute('xmlns:x14', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/main');
50 159
        $objWriter->writeAttribute('xmlns:xm', 'http://schemas.microsoft.com/office/excel/2006/main');
51 159
        $objWriter->writeAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006');
52 159
        $objWriter->writeAttribute('mc:Ignorable', 'x14ac');
53 159
        $objWriter->writeAttribute('xmlns:x14ac', 'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac');
54
55
        // sheetPr
56 159
        $this->writeSheetPr($objWriter, $worksheet);
57
58
        // Dimension
59 159
        $this->writeDimension($objWriter, $worksheet);
60
61
        // sheetViews
62 159
        $this->writeSheetViews($objWriter, $worksheet);
63
64
        // sheetFormatPr
65 159
        $this->writeSheetFormatPr($objWriter, $worksheet);
66
67
        // cols
68 159
        $this->writeCols($objWriter, $worksheet);
69
70
        // sheetData
71 159
        $this->writeSheetData($objWriter, $worksheet, $pStringTable);
1 ignored issue
show
Bug introduced by
It seems like $pStringTable can also be of type null; however, parameter $pStringTable of PhpOffice\PhpSpreadsheet...sheet::writeSheetData() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

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