Completed
Push — develop ( 557e80...8d23bd )
by Adrien
46:21
created

Worksheet::writeDrawings()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 7
nc 4
nop 3
dl 0
loc 11
ccs 8
cts 8
cp 1
crap 4
rs 9.2
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\RichText\RichText;
7
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
8
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
9
use PhpOffice\PhpSpreadsheet\Style\Conditional;
10
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
11
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
12
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView;
13
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet;
14
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
15
16
/**
17
 * @category   PhpSpreadsheet
18
 *
19
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
20
 */
21
class Worksheet extends WriterPart
22
{
23
    /**
24
     * Write worksheet to XML format.
25
     *
26
     * @param PhpspreadsheetWorksheet $pSheet
27
     * @param string[] $pStringTable
28
     * @param bool $includeCharts Flag indicating if we should write charts
29
     *
30
     * @throws WriterException
31
     *
32
     * @return string XML Output
33
     */
34 56
    public function writeWorksheet(PhpspreadsheetWorksheet $pSheet, $pStringTable = null, $includeCharts = false)
35
    {
36
        // Create XML writer
37 56
        $objWriter = null;
0 ignored issues
show
Unused Code introduced by
$objWriter is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
38 56 View Code Duplication
        if ($this->getParentWriter()->getUseDiskCaching()) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
39
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
40
        } else {
41 56
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
42
        }
43
44
        // XML header
45 56
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
46
47
        // Worksheet
48 56
        $objWriter->startElement('worksheet');
49 56
        $objWriter->writeAttribute('xml:space', 'preserve');
50 56
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
51 56
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
52
53
        // sheetPr
54 56
        $this->writeSheetPr($objWriter, $pSheet);
55
56
        // Dimension
57 56
        $this->writeDimension($objWriter, $pSheet);
58
59
        // sheetViews
60 56
        $this->writeSheetViews($objWriter, $pSheet);
61
62
        // sheetFormatPr
63 56
        $this->writeSheetFormatPr($objWriter, $pSheet);
64
65
        // cols
66 56
        $this->writeCols($objWriter, $pSheet);
67
68
        // sheetData
69 56
        $this->writeSheetData($objWriter, $pSheet, $pStringTable);
0 ignored issues
show
Bug introduced by
It seems like $pStringTable defined by parameter $pStringTable on line 34 can also be of type null; however, PhpOffice\PhpSpreadsheet...sheet::writeSheetData() does only seem to accept array<integer,string>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
70
71
        // sheetProtection
72 56
        $this->writeSheetProtection($objWriter, $pSheet);
73
74
        // protectedRanges
75 56
        $this->writeProtectedRanges($objWriter, $pSheet);
76
77
        // autoFilter
78 56
        $this->writeAutoFilter($objWriter, $pSheet);
79
80
        // mergeCells
81 56
        $this->writeMergeCells($objWriter, $pSheet);
82
83
        // conditionalFormatting
84 56
        $this->writeConditionalFormatting($objWriter, $pSheet);
85
86
        // dataValidations
87 56
        $this->writeDataValidations($objWriter, $pSheet);
88
89
        // hyperlinks
90 56
        $this->writeHyperlinks($objWriter, $pSheet);
91
92
        // Print options
93 56
        $this->writePrintOptions($objWriter, $pSheet);
94
95
        // Page margins
96 56
        $this->writePageMargins($objWriter, $pSheet);
97
98
        // Page setup
99 56
        $this->writePageSetup($objWriter, $pSheet);
100
101
        // Header / footer
102 56
        $this->writeHeaderFooter($objWriter, $pSheet);
103
104
        // Breaks
105 56
        $this->writeBreaks($objWriter, $pSheet);
106
107
        // Drawings and/or Charts
108 56
        $this->writeDrawings($objWriter, $pSheet, $includeCharts);
109
110
        // LegacyDrawing
111 56
        $this->writeLegacyDrawing($objWriter, $pSheet);
112
113
        // LegacyDrawingHF
114 56
        $this->writeLegacyDrawingHF($objWriter, $pSheet);
115
116 56
        $objWriter->endElement();
117
118
        // Return
119 56
        return $objWriter->getData();
120
    }
121
122
    /**
123
     * Write SheetPr.
124
     *
125
     * @param XMLWriter $objWriter XML Writer
126
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
127
     *
128
     * @throws WriterException
129
     */
130 56
    private function writeSheetPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
131
    {
132
        // sheetPr
133 56
        $objWriter->startElement('sheetPr');
134 56
        if ($pSheet->getParent()->hasMacros()) {
135
            //if the workbook have macros, we need to have codeName for the sheet
136
            if ($pSheet->hasCodeName() == false) {
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...
137
                $pSheet->setCodeName($pSheet->getTitle());
138
            }
139
            $objWriter->writeAttribute('codeName', $pSheet->getCodeName());
140
        }
141 56
        $autoFilterRange = $pSheet->getAutoFilter()->getRange();
142 56
        if (!empty($autoFilterRange)) {
143 3
            $objWriter->writeAttribute('filterMode', 1);
144 3
            $pSheet->getAutoFilter()->showHideRows();
145
        }
146
147
        // tabColor
148 56
        if ($pSheet->isTabColorSet()) {
149 6
            $objWriter->startElement('tabColor');
150 6
            $objWriter->writeAttribute('rgb', $pSheet->getTabColor()->getARGB());
151 6
            $objWriter->endElement();
152
        }
153
154
        // outlinePr
155 56
        $objWriter->startElement('outlinePr');
156 56
        $objWriter->writeAttribute('summaryBelow', ($pSheet->getShowSummaryBelow() ? '1' : '0'));
157 56
        $objWriter->writeAttribute('summaryRight', ($pSheet->getShowSummaryRight() ? '1' : '0'));
158 56
        $objWriter->endElement();
159
160
        // pageSetUpPr
161 56
        if ($pSheet->getPageSetup()->getFitToPage()) {
162
            $objWriter->startElement('pageSetUpPr');
163
            $objWriter->writeAttribute('fitToPage', '1');
164
            $objWriter->endElement();
165
        }
166
167 56
        $objWriter->endElement();
168 56
    }
169
170
    /**
171
     * Write Dimension.
172
     *
173
     * @param XMLWriter $objWriter XML Writer
174
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
175
     *
176
     * @throws WriterException
177
     */
178 56
    private function writeDimension(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
179
    {
180
        // dimension
181 56
        $objWriter->startElement('dimension');
182 56
        $objWriter->writeAttribute('ref', $pSheet->calculateWorksheetDimension());
183 56
        $objWriter->endElement();
184 56
    }
185
186
    /**
187
     * Write SheetViews.
188
     *
189
     * @param XMLWriter $objWriter XML Writer
190
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
191
     *
192
     * @throws WriterException
193
     */
194 56
    private function writeSheetViews(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
195
    {
196
        // sheetViews
197 56
        $objWriter->startElement('sheetViews');
198
199
        // Sheet selected?
200 56
        $sheetSelected = false;
201 56
        if ($this->getParentWriter()->getSpreadsheet()->getIndex($pSheet) == $this->getParentWriter()->getSpreadsheet()->getActiveSheetIndex()) {
202 56
            $sheetSelected = true;
203
        }
204
205
        // sheetView
206 56
        $objWriter->startElement('sheetView');
207 56
        $objWriter->writeAttribute('tabSelected', $sheetSelected ? '1' : '0');
208 56
        $objWriter->writeAttribute('workbookViewId', '0');
209
210
        // Zoom scales
211 56
        if ($pSheet->getSheetView()->getZoomScale() != 100) {
212
            $objWriter->writeAttribute('zoomScale', $pSheet->getSheetView()->getZoomScale());
213
        }
214 56
        if ($pSheet->getSheetView()->getZoomScaleNormal() != 100) {
215
            $objWriter->writeAttribute('zoomScaleNormal', $pSheet->getSheetView()->getZoomScaleNormal());
216
        }
217
218
        // View Layout Type
219 56
        if ($pSheet->getSheetView()->getView() !== SheetView::SHEETVIEW_NORMAL) {
220 1
            $objWriter->writeAttribute('view', $pSheet->getSheetView()->getView());
221
        }
222
223
        // Gridlines
224 56
        if ($pSheet->getShowGridlines()) {
225 56
            $objWriter->writeAttribute('showGridLines', 'true');
226
        } else {
227
            $objWriter->writeAttribute('showGridLines', 'false');
228
        }
229
230
        // Row and column headers
231 56
        if ($pSheet->getShowRowColHeaders()) {
232 56
            $objWriter->writeAttribute('showRowColHeaders', '1');
233
        } else {
234
            $objWriter->writeAttribute('showRowColHeaders', '0');
235
        }
236
237
        // Right-to-left
238 56
        if ($pSheet->getRightToLeft()) {
239
            $objWriter->writeAttribute('rightToLeft', 'true');
240
        }
241
242 56
        $activeCell = $pSheet->getActiveCell();
243
244
        // Pane
245 56
        $pane = '';
246 56
        $topLeftCell = $pSheet->getFreezePane();
247 56
        if (($topLeftCell != '') && ($topLeftCell != 'A1')) {
248 3
            $activeCell = $topLeftCell;
249
            // Calculate freeze coordinates
250 3
            $xSplit = $ySplit = 0;
251
252 3
            list($xSplit, $ySplit) = Cell::coordinateFromString($topLeftCell);
253 3
            $xSplit = Cell::columnIndexFromString($xSplit);
254
255
            // pane
256 3
            $pane = 'topRight';
257 3
            $objWriter->startElement('pane');
258 3
            if ($xSplit > 1) {
259
                $objWriter->writeAttribute('xSplit', $xSplit - 1);
260
            }
261 3
            if ($ySplit > 1) {
262 3
                $objWriter->writeAttribute('ySplit', $ySplit - 1);
263 3
                $pane = ($xSplit > 1) ? 'bottomRight' : 'bottomLeft';
264
            }
265 3
            $objWriter->writeAttribute('topLeftCell', $topLeftCell);
266 3
            $objWriter->writeAttribute('activePane', $pane);
267 3
            $objWriter->writeAttribute('state', 'frozen');
268 3
            $objWriter->endElement();
269
270 3
            if (($xSplit > 1) && ($ySplit > 1)) {
271
                //    Write additional selections if more than two panes (ie both an X and a Y split)
272
                $objWriter->startElement('selection');
273
                $objWriter->writeAttribute('pane', 'topRight');
274
                $objWriter->endElement();
275
                $objWriter->startElement('selection');
276
                $objWriter->writeAttribute('pane', 'bottomLeft');
277
                $objWriter->endElement();
278
            }
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 56
        $objWriter->startElement('selection');
285 56
        if ($pane != '') {
286 3
            $objWriter->writeAttribute('pane', $pane);
287
        }
288 56
        $objWriter->writeAttribute('activeCell', $activeCell);
289 56
        $objWriter->writeAttribute('sqref', $activeCell);
290 56
        $objWriter->endElement();
291
292 56
        $objWriter->endElement();
293
294 56
        $objWriter->endElement();
295 56
    }
296
297
    /**
298
     * Write SheetFormatPr.
299
     *
300
     * @param XMLWriter $objWriter XML Writer
301
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
302
     *
303
     * @throws WriterException
304
     */
305 56
    private function writeSheetFormatPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
306
    {
307
        // sheetFormatPr
308 56
        $objWriter->startElement('sheetFormatPr');
309
310
        // Default row height
311 56
        if ($pSheet->getDefaultRowDimension()->getRowHeight() >= 0) {
312 2
            $objWriter->writeAttribute('customHeight', 'true');
313 2
            $objWriter->writeAttribute('defaultRowHeight', StringHelper::formatNumber($pSheet->getDefaultRowDimension()->getRowHeight()));
314
        } else {
315 54
            $objWriter->writeAttribute('defaultRowHeight', '14.4');
316
        }
317
318
        // Set Zero Height row
319 56
        if ((string) $pSheet->getDefaultRowDimension()->getZeroHeight() == '1' ||
320 56
            strtolower((string) $pSheet->getDefaultRowDimension()->getZeroHeight()) == 'true') {
321
            $objWriter->writeAttribute('zeroHeight', '1');
322
        }
323
324
        // Default column width
325 56
        if ($pSheet->getDefaultColumnDimension()->getWidth() >= 0) {
326 1
            $objWriter->writeAttribute('defaultColWidth', StringHelper::formatNumber($pSheet->getDefaultColumnDimension()->getWidth()));
327
        }
328
329
        // Outline level - row
330 56
        $outlineLevelRow = 0;
331 56
        foreach ($pSheet->getRowDimensions() as $dimension) {
332 11
            if ($dimension->getOutlineLevel() > $outlineLevelRow) {
333 11
                $outlineLevelRow = $dimension->getOutlineLevel();
334
            }
335
        }
336 56
        $objWriter->writeAttribute('outlineLevelRow', (int) $outlineLevelRow);
337
338
        // Outline level - column
339 56
        $outlineLevelCol = 0;
340 56
        foreach ($pSheet->getColumnDimensions() as $dimension) {
341 21
            if ($dimension->getOutlineLevel() > $outlineLevelCol) {
342 21
                $outlineLevelCol = $dimension->getOutlineLevel();
343
            }
344
        }
345 56
        $objWriter->writeAttribute('outlineLevelCol', (int) $outlineLevelCol);
346
347 56
        $objWriter->endElement();
348 56
    }
349
350
    /**
351
     * Write Cols.
352
     *
353
     * @param XMLWriter $objWriter XML Writer
354
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
355
     *
356
     * @throws WriterException
357
     */
358 56
    private function writeCols(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
359
    {
360
        // cols
361 56
        if (count($pSheet->getColumnDimensions()) > 0) {
362 21
            $objWriter->startElement('cols');
363
364 21
            $pSheet->calculateColumnWidths();
365
366
            // Loop through column dimensions
367 21
            foreach ($pSheet->getColumnDimensions() as $colDimension) {
368
                // col
369 21
                $objWriter->startElement('col');
370 21
                $objWriter->writeAttribute('min', Cell::columnIndexFromString($colDimension->getColumnIndex()));
371 21
                $objWriter->writeAttribute('max', Cell::columnIndexFromString($colDimension->getColumnIndex()));
372
373 21
                if ($colDimension->getWidth() < 0) {
374
                    // No width set, apply default of 10
375 2
                    $objWriter->writeAttribute('width', '9.10');
376
                } else {
377
                    // Width set
378 21
                    $objWriter->writeAttribute('width', StringHelper::formatNumber($colDimension->getWidth()));
379
                }
380
381
                // Column visibility
382 21
                if ($colDimension->getVisible() == false) {
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...
383 3
                    $objWriter->writeAttribute('hidden', 'true');
384
                }
385
386
                // Auto size?
387 21
                if ($colDimension->getAutoSize()) {
388 8
                    $objWriter->writeAttribute('bestFit', 'true');
389
                }
390
391
                // Custom width?
392 21
                if ($colDimension->getWidth() != $pSheet->getDefaultColumnDimension()->getWidth()) {
393 21
                    $objWriter->writeAttribute('customWidth', 'true');
394
                }
395
396
                // Collapsed
397 21
                if ($colDimension->getCollapsed() == true) {
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...
398 1
                    $objWriter->writeAttribute('collapsed', 'true');
399
                }
400
401
                // Outline level
402 21
                if ($colDimension->getOutlineLevel() > 0) {
403 1
                    $objWriter->writeAttribute('outlineLevel', $colDimension->getOutlineLevel());
404
                }
405
406
                // Style
407 21
                $objWriter->writeAttribute('style', $colDimension->getXfIndex());
408
409 21
                $objWriter->endElement();
410
            }
411
412 21
            $objWriter->endElement();
413
        }
414 56
    }
415
416
    /**
417
     * Write SheetProtection.
418
     *
419
     * @param XMLWriter $objWriter XML Writer
420
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
421
     *
422
     * @throws WriterException
423
     */
424 56
    private function writeSheetProtection(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
425
    {
426
        // sheetProtection
427 56
        $objWriter->startElement('sheetProtection');
428
429 56
        if ($pSheet->getProtection()->getPassword() != '') {
430 1
            $objWriter->writeAttribute('password', $pSheet->getProtection()->getPassword());
431
        }
432
433 56
        $objWriter->writeAttribute('sheet', ($pSheet->getProtection()->getSheet() ? 'true' : 'false'));
434 56
        $objWriter->writeAttribute('objects', ($pSheet->getProtection()->getObjects() ? 'true' : 'false'));
435 56
        $objWriter->writeAttribute('scenarios', ($pSheet->getProtection()->getScenarios() ? 'true' : 'false'));
436 56
        $objWriter->writeAttribute('formatCells', ($pSheet->getProtection()->getFormatCells() ? 'true' : 'false'));
437 56
        $objWriter->writeAttribute('formatColumns', ($pSheet->getProtection()->getFormatColumns() ? 'true' : 'false'));
438 56
        $objWriter->writeAttribute('formatRows', ($pSheet->getProtection()->getFormatRows() ? 'true' : 'false'));
439 56
        $objWriter->writeAttribute('insertColumns', ($pSheet->getProtection()->getInsertColumns() ? 'true' : 'false'));
440 56
        $objWriter->writeAttribute('insertRows', ($pSheet->getProtection()->getInsertRows() ? 'true' : 'false'));
441 56
        $objWriter->writeAttribute('insertHyperlinks', ($pSheet->getProtection()->getInsertHyperlinks() ? 'true' : 'false'));
442 56
        $objWriter->writeAttribute('deleteColumns', ($pSheet->getProtection()->getDeleteColumns() ? 'true' : 'false'));
443 56
        $objWriter->writeAttribute('deleteRows', ($pSheet->getProtection()->getDeleteRows() ? 'true' : 'false'));
444 56
        $objWriter->writeAttribute('selectLockedCells', ($pSheet->getProtection()->getSelectLockedCells() ? 'true' : 'false'));
445 56
        $objWriter->writeAttribute('sort', ($pSheet->getProtection()->getSort() ? 'true' : 'false'));
446 56
        $objWriter->writeAttribute('autoFilter', ($pSheet->getProtection()->getAutoFilter() ? 'true' : 'false'));
447 56
        $objWriter->writeAttribute('pivotTables', ($pSheet->getProtection()->getPivotTables() ? 'true' : 'false'));
448 56
        $objWriter->writeAttribute('selectUnlockedCells', ($pSheet->getProtection()->getSelectUnlockedCells() ? 'true' : 'false'));
449 56
        $objWriter->endElement();
450 56
    }
451
452
    /**
453
     * Write ConditionalFormatting.
454
     *
455
     * @param XMLWriter $objWriter XML Writer
456
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
457
     *
458
     * @throws WriterException
459
     */
460 56
    private function writeConditionalFormatting(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
461
    {
462
        // Conditional id
463 56
        $id = 1;
464
465
        // Loop through styles in the current worksheet
466 56
        foreach ($pSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
467 2
            foreach ($conditionalStyles as $conditional) {
468
                // WHY was this again?
469
                // if ($this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) == '') {
0 ignored issues
show
Unused Code Comprehensibility introduced by
66% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
470
                //    continue;
471
                // }
472 2
                if ($conditional->getConditionType() != Conditional::CONDITION_NONE) {
473
                    // conditionalFormatting
474 2
                    $objWriter->startElement('conditionalFormatting');
475 2
                    $objWriter->writeAttribute('sqref', $cellCoordinate);
476
477
                    // cfRule
478 2
                    $objWriter->startElement('cfRule');
479 2
                    $objWriter->writeAttribute('type', $conditional->getConditionType());
480 2
                    $objWriter->writeAttribute('dxfId', $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()));
481 2
                    $objWriter->writeAttribute('priority', $id++);
482
483 2
                    if (($conditional->getConditionType() == Conditional::CONDITION_CELLIS || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT)
484 2
                        && $conditional->getOperatorType() != Conditional::OPERATOR_NONE) {
485 2
                        $objWriter->writeAttribute('operator', $conditional->getOperatorType());
486
                    }
487
488 2
                    if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
489 2
                        && $conditional->getText() !== null) {
490
                        $objWriter->writeAttribute('text', $conditional->getText());
491
                    }
492
493 2
                    if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
494 2
                        && $conditional->getOperatorType() == Conditional::OPERATOR_CONTAINSTEXT
495 2
                        && $conditional->getText() !== null) {
496
                        $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . ')))');
497 2 View Code Duplication
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
498 2
                        && $conditional->getOperatorType() == Conditional::OPERATOR_BEGINSWITH
499 2
                        && $conditional->getText() !== null) {
500
                        $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"');
501 2
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
502 2
                        && $conditional->getOperatorType() == Conditional::OPERATOR_ENDSWITH
503 2
                        && $conditional->getText() !== null) {
504
                        $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"');
505 2 View Code Duplication
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
506 2
                        && $conditional->getOperatorType() == Conditional::OPERATOR_NOTCONTAINS
507 2
                        && $conditional->getText() !== null) {
508
                        $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . '))');
509 2
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS
510
                        || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
511 2
                        || $conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
512 2
                        foreach ($conditional->getConditions() as $formula) {
513
                            // Formula
514 2
                            $objWriter->writeElement('formula', $formula);
515
                        }
516
                    }
517
518 2
                    $objWriter->endElement();
519
520 2
                    $objWriter->endElement();
521
                }
522
            }
523
        }
524 56
    }
525
526
    /**
527
     * Write DataValidations.
528
     *
529
     * @param XMLWriter $objWriter XML Writer
530
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
531
     *
532
     * @throws WriterException
533
     */
534 56
    private function writeDataValidations(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
535
    {
536
        // Datavalidation collection
537 56
        $dataValidationCollection = $pSheet->getDataValidationCollection();
538
539
        // Write data validations?
540 56
        if (!empty($dataValidationCollection)) {
541 2
            $dataValidationCollection = Cell::mergeRangesInCollection($dataValidationCollection);
542 2
            $objWriter->startElement('dataValidations');
543 2
            $objWriter->writeAttribute('count', count($dataValidationCollection));
544
545 2
            foreach ($dataValidationCollection as $coordinate => $dv) {
546 2
                $objWriter->startElement('dataValidation');
547
548 2
                if ($dv->getType() != '') {
549 2
                    $objWriter->writeAttribute('type', $dv->getType());
550
                }
551
552 2
                if ($dv->getErrorStyle() != '') {
553 2
                    $objWriter->writeAttribute('errorStyle', $dv->getErrorStyle());
554
                }
555
556 2
                if ($dv->getOperator() != '') {
557 2
                    $objWriter->writeAttribute('operator', $dv->getOperator());
558
                }
559
560 2
                $objWriter->writeAttribute('allowBlank', ($dv->getAllowBlank() ? '1' : '0'));
561 2
                $objWriter->writeAttribute('showDropDown', (!$dv->getShowDropDown() ? '1' : '0'));
562 2
                $objWriter->writeAttribute('showInputMessage', ($dv->getShowInputMessage() ? '1' : '0'));
563 2
                $objWriter->writeAttribute('showErrorMessage', ($dv->getShowErrorMessage() ? '1' : '0'));
564
565 2
                if ($dv->getErrorTitle() !== '') {
566 2
                    $objWriter->writeAttribute('errorTitle', $dv->getErrorTitle());
567
                }
568 2
                if ($dv->getError() !== '') {
569 2
                    $objWriter->writeAttribute('error', $dv->getError());
570
                }
571 2
                if ($dv->getPromptTitle() !== '') {
572 2
                    $objWriter->writeAttribute('promptTitle', $dv->getPromptTitle());
573
                }
574 2
                if ($dv->getPrompt() !== '') {
575 2
                    $objWriter->writeAttribute('prompt', $dv->getPrompt());
576
                }
577
578 2
                $objWriter->writeAttribute('sqref', $coordinate);
579
580 2
                if ($dv->getFormula1() !== '') {
581 2
                    $objWriter->writeElement('formula1', $dv->getFormula1());
582
                }
583 2
                if ($dv->getFormula2() !== '') {
584 1
                    $objWriter->writeElement('formula2', $dv->getFormula2());
585
                }
586
587 2
                $objWriter->endElement();
588
            }
589
590 2
            $objWriter->endElement();
591
        }
592 56
    }
593
594
    /**
595
     * Write Hyperlinks.
596
     *
597
     * @param XMLWriter $objWriter XML Writer
598
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
599
     *
600
     * @throws WriterException
601
     */
602 56
    private function writeHyperlinks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
603
    {
604
        // Hyperlink collection
605 56
        $hyperlinkCollection = $pSheet->getHyperlinkCollection();
606
607
        // Relation ID
608 56
        $relationId = 1;
609
610
        // Write hyperlinks?
611 56
        if (!empty($hyperlinkCollection)) {
612 10
            $objWriter->startElement('hyperlinks');
613
614 10
            foreach ($hyperlinkCollection as $coordinate => $hyperlink) {
615 10
                $objWriter->startElement('hyperlink');
616
617 10
                $objWriter->writeAttribute('ref', $coordinate);
618 10
                if (!$hyperlink->isInternal()) {
619 10
                    $objWriter->writeAttribute('r:id', 'rId_hyperlink_' . $relationId);
620 10
                    ++$relationId;
621
                } else {
622 7
                    $objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl()));
623
                }
624
625 10
                if ($hyperlink->getTooltip() != '') {
626 6
                    $objWriter->writeAttribute('tooltip', $hyperlink->getTooltip());
627
                }
628
629 10
                $objWriter->endElement();
630
            }
631
632 10
            $objWriter->endElement();
633
        }
634 56
    }
635
636
    /**
637
     * Write ProtectedRanges.
638
     *
639
     * @param XMLWriter $objWriter XML Writer
640
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
641
     *
642
     * @throws WriterException
643
     */
644 56
    private function writeProtectedRanges(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
645
    {
646 56
        if (count($pSheet->getProtectedCells()) > 0) {
647
            // protectedRanges
648 6
            $objWriter->startElement('protectedRanges');
649
650
            // Loop protectedRanges
651 6
            foreach ($pSheet->getProtectedCells() as $protectedCell => $passwordHash) {
652
                // protectedRange
653 6
                $objWriter->startElement('protectedRange');
654 6
                $objWriter->writeAttribute('name', 'p' . md5($protectedCell));
655 6
                $objWriter->writeAttribute('sqref', $protectedCell);
656 6
                if (!empty($passwordHash)) {
657 6
                    $objWriter->writeAttribute('password', $passwordHash);
658
                }
659 6
                $objWriter->endElement();
660
            }
661
662 6
            $objWriter->endElement();
663
        }
664 56
    }
665
666
    /**
667
     * Write MergeCells.
668
     *
669
     * @param XMLWriter $objWriter XML Writer
670
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
671
     *
672
     * @throws WriterException
673
     */
674 56
    private function writeMergeCells(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
675
    {
676 56
        if (count($pSheet->getMergeCells()) > 0) {
677
            // mergeCells
678 11
            $objWriter->startElement('mergeCells');
679
680
            // Loop mergeCells
681 11
            foreach ($pSheet->getMergeCells() as $mergeCell) {
682
                // mergeCell
683 11
                $objWriter->startElement('mergeCell');
684 11
                $objWriter->writeAttribute('ref', $mergeCell);
685 11
                $objWriter->endElement();
686
            }
687
688 11
            $objWriter->endElement();
689
        }
690 56
    }
691
692
    /**
693
     * Write PrintOptions.
694
     *
695
     * @param XMLWriter $objWriter XML Writer
696
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
697
     *
698
     * @throws WriterException
699
     */
700 56
    private function writePrintOptions(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
701
    {
702
        // printOptions
703 56
        $objWriter->startElement('printOptions');
704
705 56
        $objWriter->writeAttribute('gridLines', ($pSheet->getPrintGridlines() ? 'true' : 'false'));
706 56
        $objWriter->writeAttribute('gridLinesSet', 'true');
707
708 56
        if ($pSheet->getPageSetup()->getHorizontalCentered()) {
709
            $objWriter->writeAttribute('horizontalCentered', 'true');
710
        }
711
712 56
        if ($pSheet->getPageSetup()->getVerticalCentered()) {
713
            $objWriter->writeAttribute('verticalCentered', 'true');
714
        }
715
716 56
        $objWriter->endElement();
717 56
    }
718
719
    /**
720
     * Write PageMargins.
721
     *
722
     * @param XMLWriter $objWriter XML Writer
723
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
724
     *
725
     * @throws WriterException
726
     */
727 56
    private function writePageMargins(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
728
    {
729
        // pageMargins
730 56
        $objWriter->startElement('pageMargins');
731 56
        $objWriter->writeAttribute('left', StringHelper::formatNumber($pSheet->getPageMargins()->getLeft()));
732 56
        $objWriter->writeAttribute('right', StringHelper::formatNumber($pSheet->getPageMargins()->getRight()));
733 56
        $objWriter->writeAttribute('top', StringHelper::formatNumber($pSheet->getPageMargins()->getTop()));
734 56
        $objWriter->writeAttribute('bottom', StringHelper::formatNumber($pSheet->getPageMargins()->getBottom()));
735 56
        $objWriter->writeAttribute('header', StringHelper::formatNumber($pSheet->getPageMargins()->getHeader()));
736 56
        $objWriter->writeAttribute('footer', StringHelper::formatNumber($pSheet->getPageMargins()->getFooter()));
737 56
        $objWriter->endElement();
738 56
    }
739
740
    /**
741
     * Write AutoFilter.
742
     *
743
     * @param XMLWriter $objWriter XML Writer
744
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
745
     *
746
     * @throws WriterException
747
     */
748 56
    private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
749
    {
750 56
        $autoFilterRange = $pSheet->getAutoFilter()->getRange();
751 56
        if (!empty($autoFilterRange)) {
752
            // autoFilter
753 3
            $objWriter->startElement('autoFilter');
754
755
            // Strip any worksheet reference from the filter coordinates
756 3
            $range = Cell::splitRange($autoFilterRange);
757 3
            $range = $range[0];
758
            //    Strip any worksheet ref
759 3 View Code Duplication
            if (strpos($range[0], '!') !== false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
760
                list($ws, $range[0]) = explode('!', $range[0]);
0 ignored issues
show
Unused Code introduced by
The assignment to $ws is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
761
            }
762 3
            $range = implode(':', $range);
763
764 3
            $objWriter->writeAttribute('ref', str_replace('$', '', $range));
765
766 3
            $columns = $pSheet->getAutoFilter()->getColumns();
767 3
            if (count($columns) > 0) {
768 2
                foreach ($columns as $columnID => $column) {
769 2
                    $rules = $column->getRules();
770 2
                    if (count($rules) > 0) {
771 2
                        $objWriter->startElement('filterColumn');
772 2
                        $objWriter->writeAttribute('colId', $pSheet->getAutoFilter()->getColumnOffset($columnID));
773
774 2
                        $objWriter->startElement($column->getFilterType());
775 2
                        if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) {
776 1
                            $objWriter->writeAttribute('and', 1);
777
                        }
778
779 2
                        foreach ($rules as $rule) {
780 2
                            if (($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) &&
781 2
                                ($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) &&
782 2
                                ($rule->getValue() === '')) {
783
                                //    Filter rule for Blanks
784 1
                                $objWriter->writeAttribute('blank', 1);
785 2
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) {
786
                                //    Dynamic Filter Rule
787 1
                                $objWriter->writeAttribute('type', $rule->getGrouping());
788 1
                                $val = $column->getAttribute('val');
789 1
                                if ($val !== null) {
790 1
                                    $objWriter->writeAttribute('val', $val);
791
                                }
792 1
                                $maxVal = $column->getAttribute('maxVal');
793 1
                                if ($maxVal !== null) {
794 1
                                    $objWriter->writeAttribute('maxVal', $maxVal);
795
                                }
796 2
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) {
797
                                //    Top 10 Filter Rule
798
                                $objWriter->writeAttribute('val', $rule->getValue());
799
                                $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0'));
800
                                $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0'));
801
                            } else {
802
                                //    Filter, DateGroupItem or CustomFilter
803 2
                                $objWriter->startElement($rule->getRuleType());
804
805 2
                                if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) {
806 1
                                    $objWriter->writeAttribute('operator', $rule->getOperator());
807
                                }
808 2
                                if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) {
809
                                    // Date Group filters
810 1
                                    foreach ($rule->getValue() as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $rule->getValue() of type string is not traversable.
Loading history...
811 1
                                        if ($value > '') {
812 1
                                            $objWriter->writeAttribute($key, $value);
813
                                        }
814
                                    }
815 1
                                    $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping());
816
                                } else {
817 2
                                    $objWriter->writeAttribute('val', $rule->getValue());
818
                                }
819
820 2
                                $objWriter->endElement();
821
                            }
822
                        }
823
824 2
                        $objWriter->endElement();
825
826 2
                        $objWriter->endElement();
827
                    }
828
                }
829
            }
830 3
            $objWriter->endElement();
831
        }
832 56
    }
833
834
    /**
835
     * Write PageSetup.
836
     *
837
     * @param XMLWriter $objWriter XML Writer
838
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
839
     *
840
     * @throws WriterException
841
     */
842 56
    private function writePageSetup(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
843
    {
844
        // pageSetup
845 56
        $objWriter->startElement('pageSetup');
846 56
        $objWriter->writeAttribute('paperSize', $pSheet->getPageSetup()->getPaperSize());
847 56
        $objWriter->writeAttribute('orientation', $pSheet->getPageSetup()->getOrientation());
848
849 56
        if ($pSheet->getPageSetup()->getScale() !== null) {
850 56
            $objWriter->writeAttribute('scale', $pSheet->getPageSetup()->getScale());
851
        }
852 56
        if ($pSheet->getPageSetup()->getFitToHeight() !== null) {
853 56
            $objWriter->writeAttribute('fitToHeight', $pSheet->getPageSetup()->getFitToHeight());
854
        } else {
855
            $objWriter->writeAttribute('fitToHeight', '0');
856
        }
857 56
        if ($pSheet->getPageSetup()->getFitToWidth() !== null) {
858 56
            $objWriter->writeAttribute('fitToWidth', $pSheet->getPageSetup()->getFitToWidth());
859
        } else {
860
            $objWriter->writeAttribute('fitToWidth', '0');
861
        }
862 56
        if ($pSheet->getPageSetup()->getFirstPageNumber() !== null) {
863
            $objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber());
864
            $objWriter->writeAttribute('useFirstPageNumber', '1');
865
        }
866
867 56
        $objWriter->endElement();
868 56
    }
869
870
    /**
871
     * Write Header / Footer.
872
     *
873
     * @param XMLWriter $objWriter XML Writer
874
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
875
     *
876
     * @throws WriterException
877
     */
878 56
    private function writeHeaderFooter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
879
    {
880
        // headerFooter
881 56
        $objWriter->startElement('headerFooter');
882 56
        $objWriter->writeAttribute('differentOddEven', ($pSheet->getHeaderFooter()->getDifferentOddEven() ? 'true' : 'false'));
883 56
        $objWriter->writeAttribute('differentFirst', ($pSheet->getHeaderFooter()->getDifferentFirst() ? 'true' : 'false'));
884 56
        $objWriter->writeAttribute('scaleWithDoc', ($pSheet->getHeaderFooter()->getScaleWithDocument() ? 'true' : 'false'));
885 56
        $objWriter->writeAttribute('alignWithMargins', ($pSheet->getHeaderFooter()->getAlignWithMargins() ? 'true' : 'false'));
886
887 56
        $objWriter->writeElement('oddHeader', $pSheet->getHeaderFooter()->getOddHeader());
888 56
        $objWriter->writeElement('oddFooter', $pSheet->getHeaderFooter()->getOddFooter());
889 56
        $objWriter->writeElement('evenHeader', $pSheet->getHeaderFooter()->getEvenHeader());
890 56
        $objWriter->writeElement('evenFooter', $pSheet->getHeaderFooter()->getEvenFooter());
891 56
        $objWriter->writeElement('firstHeader', $pSheet->getHeaderFooter()->getFirstHeader());
892 56
        $objWriter->writeElement('firstFooter', $pSheet->getHeaderFooter()->getFirstFooter());
893 56
        $objWriter->endElement();
894 56
    }
895
896
    /**
897
     * Write Breaks.
898
     *
899
     * @param XMLWriter $objWriter XML Writer
900
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
901
     *
902
     * @throws WriterException
903
     */
904 56
    private function writeBreaks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
905
    {
906
        // Get row and column breaks
907 56
        $aRowBreaks = [];
908 56
        $aColumnBreaks = [];
909 56
        foreach ($pSheet->getBreaks() as $cell => $breakType) {
910 1
            if ($breakType == PhpspreadsheetWorksheet::BREAK_ROW) {
911 1
                $aRowBreaks[] = $cell;
912
            } elseif ($breakType == PhpspreadsheetWorksheet::BREAK_COLUMN) {
913 1
                $aColumnBreaks[] = $cell;
914
            }
915
        }
916
917
        // rowBreaks
918 56 View Code Duplication
        if (!empty($aRowBreaks)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
919 1
            $objWriter->startElement('rowBreaks');
920 1
            $objWriter->writeAttribute('count', count($aRowBreaks));
921 1
            $objWriter->writeAttribute('manualBreakCount', count($aRowBreaks));
922
923 1
            foreach ($aRowBreaks as $cell) {
924 1
                $coords = Cell::coordinateFromString($cell);
925
926 1
                $objWriter->startElement('brk');
927 1
                $objWriter->writeAttribute('id', $coords[1]);
928 1
                $objWriter->writeAttribute('man', '1');
929 1
                $objWriter->endElement();
930
            }
931
932 1
            $objWriter->endElement();
933
        }
934
935
        // Second, write column breaks
936 56 View Code Duplication
        if (!empty($aColumnBreaks)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
937
            $objWriter->startElement('colBreaks');
938
            $objWriter->writeAttribute('count', count($aColumnBreaks));
939
            $objWriter->writeAttribute('manualBreakCount', count($aColumnBreaks));
940
941
            foreach ($aColumnBreaks as $cell) {
942
                $coords = Cell::coordinateFromString($cell);
943
944
                $objWriter->startElement('brk');
945
                $objWriter->writeAttribute('id', Cell::columnIndexFromString($coords[0]) - 1);
946
                $objWriter->writeAttribute('man', '1');
947
                $objWriter->endElement();
948
            }
949
950
            $objWriter->endElement();
951
        }
952 56
    }
953
954
    /**
955
     * Write SheetData.
956
     *
957
     * @param XMLWriter $objWriter XML Writer
958
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
959
     * @param string[] $pStringTable String table
960
     *
961
     * @throws WriterException
962
     */
963 56
    private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, array $pStringTable)
964
    {
965
        // Flipped stringtable, for faster index searching
966 56
        $aFlippedStringTable = $this->getParentWriter()->getWriterPart('stringtable')->flipStringTable($pStringTable);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class PhpOffice\PhpSpreadsheet\Writer\Xlsx\WriterPart as the method flipStringTable() does only exist in the following sub-classes of PhpOffice\PhpSpreadsheet\Writer\Xlsx\WriterPart: PhpOffice\PhpSpreadsheet\Writer\Xlsx\StringTable. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

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

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
1097 8
                        $objWriter->endElement();
1098
                    }
1099
1100 8
                    break;
1101 55
                case 's':            // String
1102 50
                    if (!$cellValue instanceof RichText) {
1103 50
                        if (isset($pFlippedStringTable[$cellValue])) {
1104 50
                            $objWriter->writeElement('v', $pFlippedStringTable[$cellValue]);
1105
                        }
1106 2
                    } elseif ($cellValue instanceof RichText) {
1107 2
                        $objWriter->writeElement('v', $pFlippedStringTable[$cellValue->getHashCode()]);
1108
                    }
1109
1110 50
                    break;
1111 48
                case 'f':            // Formula
1112 18
                    $attributes = $pCell->getFormulaAttributes();
1113 18
                    if ($attributes['t'] == 'array') {
1114
                        $objWriter->startElement('f');
1115
                        $objWriter->writeAttribute('t', 'array');
1116
                        $objWriter->writeAttribute('ref', $pCellAddress);
1117
                        $objWriter->writeAttribute('aca', '1');
1118
                        $objWriter->writeAttribute('ca', '1');
1119
                        $objWriter->text(substr($cellValue, 1));
1120
                        $objWriter->endElement();
1121
                    } else {
1122 18
                        $objWriter->writeElement('f', substr($cellValue, 1));
1123
                    }
1124 18
                    if ($this->getParentWriter()->getOffice2003Compatibility() === false) {
1125 18
                        if ($this->getParentWriter()->getPreCalculateFormulas()) {
1126 18
                            if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) != '#') {
1127 18
                                $objWriter->writeElement('v', StringHelper::formatNumber($calculatedValue));
0 ignored issues
show
Bug introduced by
The variable $calculatedValue does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1128
                            } else {
1129 18
                                $objWriter->writeElement('v', '0');
1130
                            }
1131
                        } else {
1132
                            $objWriter->writeElement('v', '0');
1133
                        }
1134
                    }
1135
1136 18
                    break;
1137 47
                case 'n':            // Numeric
1138
                    // force point as decimal separator in case current locale uses comma
1139 39
                    $objWriter->writeElement('v', str_replace(',', '.', $cellValue));
1140
1141 39
                    break;
1142 26
                case 'b':            // Boolean
1143 8
                    $objWriter->writeElement('v', ($cellValue ? '1' : '0'));
1144
1145 8
                    break;
1146 22
                case 'e':            // Error
1147
                    if (substr($cellValue, 0, 1) == '=') {
1148
                        $objWriter->writeElement('f', substr($cellValue, 1));
1149
                        $objWriter->writeElement('v', substr($cellValue, 1));
1150
                    } else {
1151
                        $objWriter->writeElement('v', $cellValue);
1152
                    }
1153
1154
                    break;
1155
            }
1156
        }
1157
1158 56
        $objWriter->endElement();
1159 56
    }
1160
1161
    /**
1162
     * Write Drawings.
1163
     *
1164
     * @param XMLWriter $objWriter XML Writer
1165
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1166
     * @param bool $includeCharts Flag indicating if we should include drawing details for charts
1167
     *
1168
     * @throws WriterException
1169
     */
1170 56
    private function writeDrawings(XMLWriter $objWriter = null, PhpspreadsheetWorksheet $pSheet = null, $includeCharts = false)
1171
    {
1172 56
        $chartCount = ($includeCharts) ? $pSheet->getChartCollection()->count() : 0;
0 ignored issues
show
Bug introduced by
It seems like $pSheet is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
1173
        // If sheet contains drawings, add the relationships
1174 56
        if (($pSheet->getDrawingCollection()->count() > 0) ||
1175 56
            ($chartCount > 0)) {
1176 22
            $objWriter->startElement('drawing');
0 ignored issues
show
Bug introduced by
It seems like $objWriter is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
1177 22
            $objWriter->writeAttribute('r:id', 'rId1');
1178 22
            $objWriter->endElement();
1179
        }
1180 56
    }
1181
1182
    /**
1183
     * Write LegacyDrawing.
1184
     *
1185
     * @param XMLWriter $objWriter XML Writer
1186
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1187
     *
1188
     * @throws WriterException
1189
     */
1190 56
    private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
1191
    {
1192
        // If sheet contains comments, add the relationships
1193 56
        if (count($pSheet->getComments()) > 0) {
1194 9
            $objWriter->startElement('legacyDrawing');
1195 9
            $objWriter->writeAttribute('r:id', 'rId_comments_vml1');
1196 9
            $objWriter->endElement();
1197
        }
1198 56
    }
1199
1200
    /**
1201
     * Write LegacyDrawingHF.
1202
     *
1203
     * @param XMLWriter $objWriter XML Writer
1204
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1205
     *
1206
     * @throws WriterException
1207
     */
1208 56
    private function writeLegacyDrawingHF(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
1209
    {
1210
        // If sheet contains images, add the relationships
1211 56
        if (count($pSheet->getHeaderFooter()->getImages()) > 0) {
1212 1
            $objWriter->startElement('legacyDrawingHF');
1213 1
            $objWriter->writeAttribute('r:id', 'rId_headerfooter_vml1');
1214 1
            $objWriter->endElement();
1215
        }
1216 56
    }
1217
}
1218