Completed
Push — develop ( 44e246...6e4e0a )
by Adrien
19:07
created

Worksheet::writeWorksheet()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 90
Code Lines 36

Duplication

Lines 5
Ratio 5.56 %

Code Coverage

Tests 33
CRAP Score 3.0016

Importance

Changes 0
Metric Value
cc 3
eloc 36
nc 3
nop 3
dl 5
loc 90
rs 8.5454
c 0
b 0
f 0
ccs 33
cts 35
cp 0.9429
crap 3.0016

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
4
5
/*
6
 * PhpSpreadsheet.
7
 *
8
 * Copyright (c) 2006 - 2015 PhpSpreadsheet
9
 *
10
 * This library is free software; you can redistribute it and/or
11
 * modify it under the terms of the GNU Lesser General Public
12
 * License as published by the Free Software Foundation; either
13
 * version 2.1 of the License, or (at your option) any later version.
14
 *
15
 * This library is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
 * Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public
21
 * License along with this library; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23
 *
24
 * @category   PhpSpreadsheet
25
 *
26
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
27
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
28
 */
29
use PhpOffice\PhpSpreadsheet\Cell;
30
use PhpOffice\PhpSpreadsheet\RichText;
31
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
32
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
33
use PhpOffice\PhpSpreadsheet\Style\Conditional;
34
use PhpOffice\PhpSpreadsheet\Worksheet as PhpspreadsheetWorksheet;
35
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
36
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
37
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView;
38
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
39
40
/**
41
 * @category   PhpSpreadsheet
42
 *
43
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
44
 */
45
class Worksheet extends WriterPart
46
{
47
    /**
48
     * Write worksheet to XML format.
49
     *
50
     * @param PhpspreadsheetWorksheet $pSheet
51
     * @param string[] $pStringTable
52
     * @param bool $includeCharts Flag indicating if we should write charts
53
     *
54
     * @throws WriterException
55
     *
56
     * @return string XML Output
57
     */
58 55
    public function writeWorksheet($pSheet = null, $pStringTable = null, $includeCharts = false)
59
    {
60 55
        if (!is_null($pSheet)) {
61
            // Create XML writer
62 55
            $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...
63 55 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...
64
                $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
65
            } else {
66 55
                $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
67
            }
68
69
            // XML header
70 55
            $objWriter->startDocument('1.0', 'UTF-8', 'yes');
71
72
            // Worksheet
73 55
            $objWriter->startElement('worksheet');
74 55
            $objWriter->writeAttribute('xml:space', 'preserve');
75 55
            $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
76 55
            $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
77
78
                // sheetPr
79 55
                $this->writeSheetPr($objWriter, $pSheet);
80
81
                // Dimension
82 55
                $this->writeDimension($objWriter, $pSheet);
83
84
                // sheetViews
85 55
                $this->writeSheetViews($objWriter, $pSheet);
86
87
                // sheetFormatPr
88 55
                $this->writeSheetFormatPr($objWriter, $pSheet);
89
90
                // cols
91 55
                $this->writeCols($objWriter, $pSheet);
92
93
                // sheetData
94 55
                $this->writeSheetData($objWriter, $pSheet, $pStringTable);
0 ignored issues
show
Bug introduced by
It seems like $pStringTable defined by parameter $pStringTable on line 58 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...
95
96
                // sheetProtection
97 55
                $this->writeSheetProtection($objWriter, $pSheet);
98
99
                // protectedRanges
100 55
                $this->writeProtectedRanges($objWriter, $pSheet);
101
102
                // autoFilter
103 55
                $this->writeAutoFilter($objWriter, $pSheet);
104
105
                // mergeCells
106 55
                $this->writeMergeCells($objWriter, $pSheet);
107
108
                // conditionalFormatting
109 55
                $this->writeConditionalFormatting($objWriter, $pSheet);
110
111
                // dataValidations
112 55
                $this->writeDataValidations($objWriter, $pSheet);
113
114
                // hyperlinks
115 55
                $this->writeHyperlinks($objWriter, $pSheet);
116
117
                // Print options
118 55
                $this->writePrintOptions($objWriter, $pSheet);
119
120
                // Page margins
121 55
                $this->writePageMargins($objWriter, $pSheet);
122
123
                // Page setup
124 55
                $this->writePageSetup($objWriter, $pSheet);
125
126
                // Header / footer
127 55
                $this->writeHeaderFooter($objWriter, $pSheet);
128
129
                // Breaks
130 55
                $this->writeBreaks($objWriter, $pSheet);
131
132
                // Drawings and/or Charts
133 55
                $this->writeDrawings($objWriter, $pSheet, $includeCharts);
134
135
                // LegacyDrawing
136 55
                $this->writeLegacyDrawing($objWriter, $pSheet);
137
138
                // LegacyDrawingHF
139 55
                $this->writeLegacyDrawingHF($objWriter, $pSheet);
140
141 55
            $objWriter->endElement();
142
143
            // Return
144 55
            return $objWriter->getData();
145
        }
146
        throw new WriterException('Invalid \\PhpOffice\\PhpSpreadsheet\\Worksheet object passed.');
147
    }
148
149
    /**
150
     * Write SheetPr.
151
     *
152
     * @param XMLWriter $objWriter XML Writer
153
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
154
     *
155
     * @throws WriterException
156
     */
157 55
    private function writeSheetPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
158
    {
159
        // sheetPr
160 55
        $objWriter->startElement('sheetPr');
161 55
        if ($pSheet->getParent()->hasMacros()) {
162
            //if the workbook have macros, we need to have codeName for the sheet
163
            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...
164
                $pSheet->setCodeName($pSheet->getTitle());
165
            }
166
            $objWriter->writeAttribute('codeName', $pSheet->getCodeName());
167
        }
168 55
        $autoFilterRange = $pSheet->getAutoFilter()->getRange();
169 55
        if (!empty($autoFilterRange)) {
170 3
            $objWriter->writeAttribute('filterMode', 1);
171 3
            $pSheet->getAutoFilter()->showHideRows();
172
        }
173
174
        // tabColor
175 55
        if ($pSheet->isTabColorSet()) {
176 6
            $objWriter->startElement('tabColor');
177 6
            $objWriter->writeAttribute('rgb', $pSheet->getTabColor()->getARGB());
178 6
            $objWriter->endElement();
179
        }
180
181
        // outlinePr
182 55
        $objWriter->startElement('outlinePr');
183 55
        $objWriter->writeAttribute('summaryBelow', ($pSheet->getShowSummaryBelow() ? '1' : '0'));
184 55
        $objWriter->writeAttribute('summaryRight', ($pSheet->getShowSummaryRight() ? '1' : '0'));
185 55
        $objWriter->endElement();
186
187
        // pageSetUpPr
188 55
        if ($pSheet->getPageSetup()->getFitToPage()) {
189
            $objWriter->startElement('pageSetUpPr');
190
            $objWriter->writeAttribute('fitToPage', '1');
191
            $objWriter->endElement();
192
        }
193
194 55
        $objWriter->endElement();
195 55
    }
196
197
    /**
198
     * Write Dimension.
199
     *
200
     * @param XMLWriter $objWriter XML Writer
201
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
202
     *
203
     * @throws WriterException
204
     */
205 55
    private function writeDimension(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
206
    {
207
        // dimension
208 55
        $objWriter->startElement('dimension');
209 55
        $objWriter->writeAttribute('ref', $pSheet->calculateWorksheetDimension());
210 55
        $objWriter->endElement();
211 55
    }
212
213
    /**
214
     * Write SheetViews.
215
     *
216
     * @param XMLWriter $objWriter XML Writer
217
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
218
     *
219
     * @throws WriterException
220
     */
221 55
    private function writeSheetViews(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
222
    {
223
        // sheetViews
224 55
        $objWriter->startElement('sheetViews');
225
226
        // Sheet selected?
227 55
        $sheetSelected = false;
228 55
        if ($this->getParentWriter()->getSpreadsheet()->getIndex($pSheet) == $this->getParentWriter()->getSpreadsheet()->getActiveSheetIndex()) {
229 55
            $sheetSelected = true;
230
        }
231
232
        // sheetView
233 55
        $objWriter->startElement('sheetView');
234 55
        $objWriter->writeAttribute('tabSelected', $sheetSelected ? '1' : '0');
235 55
        $objWriter->writeAttribute('workbookViewId', '0');
236
237
        // Zoom scales
238 55
        if ($pSheet->getSheetView()->getZoomScale() != 100) {
239
            $objWriter->writeAttribute('zoomScale', $pSheet->getSheetView()->getZoomScale());
240
        }
241 55
        if ($pSheet->getSheetView()->getZoomScaleNormal() != 100) {
242
            $objWriter->writeAttribute('zoomScaleNormal', $pSheet->getSheetView()->getZoomScaleNormal());
243
        }
244
245
        // View Layout Type
246 55
        if ($pSheet->getSheetView()->getView() !== SheetView::SHEETVIEW_NORMAL) {
247 1
            $objWriter->writeAttribute('view', $pSheet->getSheetView()->getView());
248
        }
249
250
        // Gridlines
251 55
        if ($pSheet->getShowGridlines()) {
252 55
            $objWriter->writeAttribute('showGridLines', 'true');
253
        } else {
254
            $objWriter->writeAttribute('showGridLines', 'false');
255
        }
256
257
        // Row and column headers
258 55
        if ($pSheet->getShowRowColHeaders()) {
259 55
            $objWriter->writeAttribute('showRowColHeaders', '1');
260
        } else {
261
            $objWriter->writeAttribute('showRowColHeaders', '0');
262
        }
263
264
        // Right-to-left
265 55
        if ($pSheet->getRightToLeft()) {
266
            $objWriter->writeAttribute('rightToLeft', 'true');
267
        }
268
269 55
        $activeCell = $pSheet->getActiveCell();
270
271
        // Pane
272 55
        $pane = '';
273 55
        $topLeftCell = $pSheet->getFreezePane();
274 55
        if (($topLeftCell != '') && ($topLeftCell != 'A1')) {
275 3
            $activeCell = $topLeftCell;
276
            // Calculate freeze coordinates
277 3
            $xSplit = $ySplit = 0;
278
279 3
            list($xSplit, $ySplit) = Cell::coordinateFromString($topLeftCell);
280 3
            $xSplit = Cell::columnIndexFromString($xSplit);
281
282
            // pane
283 3
            $pane = 'topRight';
284 3
            $objWriter->startElement('pane');
285 3
            if ($xSplit > 1) {
286
                $objWriter->writeAttribute('xSplit', $xSplit - 1);
287
            }
288 3
            if ($ySplit > 1) {
289 3
                $objWriter->writeAttribute('ySplit', $ySplit - 1);
290 3
                $pane = ($xSplit > 1) ? 'bottomRight' : 'bottomLeft';
291
            }
292 3
            $objWriter->writeAttribute('topLeftCell', $topLeftCell);
293 3
            $objWriter->writeAttribute('activePane', $pane);
294 3
            $objWriter->writeAttribute('state', 'frozen');
295 3
            $objWriter->endElement();
296
297 3
            if (($xSplit > 1) && ($ySplit > 1)) {
298
                //    Write additional selections if more than two panes (ie both an X and a Y split)
299
                $objWriter->startElement('selection');
300
                $objWriter->writeAttribute('pane', 'topRight');
301
                $objWriter->endElement();
302
                $objWriter->startElement('selection');
303
                $objWriter->writeAttribute('pane', 'bottomLeft');
304
                $objWriter->endElement();
305
            }
306
        }
307
308
        // Selection
0 ignored issues
show
Unused Code Comprehensibility introduced by
44% 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...
309
//      if ($pane != '') {
310
        // Only need to write selection element if we have a split pane
311
        // We cheat a little by over-riding the active cell selection, setting it to the split cell
312 55
        $objWriter->startElement('selection');
313 55
        if ($pane != '') {
314 3
            $objWriter->writeAttribute('pane', $pane);
315
        }
316 55
        $objWriter->writeAttribute('activeCell', $activeCell);
317 55
        $objWriter->writeAttribute('sqref', $activeCell);
318 55
        $objWriter->endElement();
319
//      }
320
321 55
        $objWriter->endElement();
322
323 55
        $objWriter->endElement();
324 55
    }
325
326
    /**
327
     * Write SheetFormatPr.
328
     *
329
     * @param XMLWriter $objWriter XML Writer
330
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
331
     *
332
     * @throws WriterException
333
     */
334 55
    private function writeSheetFormatPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
335
    {
336
        // sheetFormatPr
337 55
        $objWriter->startElement('sheetFormatPr');
338
339
        // Default row height
340 55
        if ($pSheet->getDefaultRowDimension()->getRowHeight() >= 0) {
341 2
            $objWriter->writeAttribute('customHeight', 'true');
342 2
            $objWriter->writeAttribute('defaultRowHeight', StringHelper::formatNumber($pSheet->getDefaultRowDimension()->getRowHeight()));
343
        } else {
344 53
            $objWriter->writeAttribute('defaultRowHeight', '14.4');
345
        }
346
347
        // Set Zero Height row
348 55
        if ((string) $pSheet->getDefaultRowDimension()->getZeroHeight() == '1' ||
349 55
            strtolower((string) $pSheet->getDefaultRowDimension()->getZeroHeight()) == 'true') {
350
            $objWriter->writeAttribute('zeroHeight', '1');
351
        }
352
353
        // Default column width
354 55
        if ($pSheet->getDefaultColumnDimension()->getWidth() >= 0) {
355 1
            $objWriter->writeAttribute('defaultColWidth', StringHelper::formatNumber($pSheet->getDefaultColumnDimension()->getWidth()));
356
        }
357
358
        // Outline level - row
359 55
        $outlineLevelRow = 0;
360 55
        foreach ($pSheet->getRowDimensions() as $dimension) {
361 11
            if ($dimension->getOutlineLevel() > $outlineLevelRow) {
362 11
                $outlineLevelRow = $dimension->getOutlineLevel();
363
            }
364
        }
365 55
        $objWriter->writeAttribute('outlineLevelRow', (int) $outlineLevelRow);
366
367
        // Outline level - column
368 55
        $outlineLevelCol = 0;
369 55
        foreach ($pSheet->getColumnDimensions() as $dimension) {
370 21
            if ($dimension->getOutlineLevel() > $outlineLevelCol) {
371 21
                $outlineLevelCol = $dimension->getOutlineLevel();
372
            }
373
        }
374 55
        $objWriter->writeAttribute('outlineLevelCol', (int) $outlineLevelCol);
375
376 55
        $objWriter->endElement();
377 55
    }
378
379
    /**
380
     * Write Cols.
381
     *
382
     * @param XMLWriter $objWriter XML Writer
383
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
384
     *
385
     * @throws WriterException
386
     */
387 55
    private function writeCols(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
388
    {
389
        // cols
390 55
        if (count($pSheet->getColumnDimensions()) > 0) {
391 21
            $objWriter->startElement('cols');
392
393 21
            $pSheet->calculateColumnWidths();
394
395
            // Loop through column dimensions
396 21
            foreach ($pSheet->getColumnDimensions() as $colDimension) {
397
                // col
398 21
                $objWriter->startElement('col');
399 21
                $objWriter->writeAttribute('min', Cell::columnIndexFromString($colDimension->getColumnIndex()));
400 21
                $objWriter->writeAttribute('max', Cell::columnIndexFromString($colDimension->getColumnIndex()));
401
402 21
                if ($colDimension->getWidth() < 0) {
403
                    // No width set, apply default of 10
404 2
                    $objWriter->writeAttribute('width', '9.10');
405
                } else {
406
                    // Width set
407 21
                    $objWriter->writeAttribute('width', StringHelper::formatNumber($colDimension->getWidth()));
408
                }
409
410
                // Column visibility
411 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...
412 3
                    $objWriter->writeAttribute('hidden', 'true');
413
                }
414
415
                // Auto size?
416 21
                if ($colDimension->getAutoSize()) {
417 8
                    $objWriter->writeAttribute('bestFit', 'true');
418
                }
419
420
                // Custom width?
421 21
                if ($colDimension->getWidth() != $pSheet->getDefaultColumnDimension()->getWidth()) {
422 21
                    $objWriter->writeAttribute('customWidth', 'true');
423
                }
424
425
                // Collapsed
426 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...
427 1
                    $objWriter->writeAttribute('collapsed', 'true');
428
                }
429
430
                // Outline level
431 21
                if ($colDimension->getOutlineLevel() > 0) {
432 1
                    $objWriter->writeAttribute('outlineLevel', $colDimension->getOutlineLevel());
433
                }
434
435
                // Style
436 21
                $objWriter->writeAttribute('style', $colDimension->getXfIndex());
437
438 21
                $objWriter->endElement();
439
            }
440
441 21
            $objWriter->endElement();
442
        }
443 55
    }
444
445
    /**
446
     * Write SheetProtection.
447
     *
448
     * @param XMLWriter $objWriter XML Writer
449
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
450
     *
451
     * @throws WriterException
452
     */
453 55
    private function writeSheetProtection(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
454
    {
455
        // sheetProtection
456 55
        $objWriter->startElement('sheetProtection');
457
458 55
        if ($pSheet->getProtection()->getPassword() != '') {
459 1
            $objWriter->writeAttribute('password', $pSheet->getProtection()->getPassword());
460
        }
461
462 55
        $objWriter->writeAttribute('sheet', ($pSheet->getProtection()->getSheet() ? 'true' : 'false'));
463 55
        $objWriter->writeAttribute('objects', ($pSheet->getProtection()->getObjects() ? 'true' : 'false'));
464 55
        $objWriter->writeAttribute('scenarios', ($pSheet->getProtection()->getScenarios() ? 'true' : 'false'));
465 55
        $objWriter->writeAttribute('formatCells', ($pSheet->getProtection()->getFormatCells() ? 'true' : 'false'));
466 55
        $objWriter->writeAttribute('formatColumns', ($pSheet->getProtection()->getFormatColumns() ? 'true' : 'false'));
467 55
        $objWriter->writeAttribute('formatRows', ($pSheet->getProtection()->getFormatRows() ? 'true' : 'false'));
468 55
        $objWriter->writeAttribute('insertColumns', ($pSheet->getProtection()->getInsertColumns() ? 'true' : 'false'));
469 55
        $objWriter->writeAttribute('insertRows', ($pSheet->getProtection()->getInsertRows() ? 'true' : 'false'));
470 55
        $objWriter->writeAttribute('insertHyperlinks', ($pSheet->getProtection()->getInsertHyperlinks() ? 'true' : 'false'));
471 55
        $objWriter->writeAttribute('deleteColumns', ($pSheet->getProtection()->getDeleteColumns() ? 'true' : 'false'));
472 55
        $objWriter->writeAttribute('deleteRows', ($pSheet->getProtection()->getDeleteRows() ? 'true' : 'false'));
473 55
        $objWriter->writeAttribute('selectLockedCells', ($pSheet->getProtection()->getSelectLockedCells() ? 'true' : 'false'));
474 55
        $objWriter->writeAttribute('sort', ($pSheet->getProtection()->getSort() ? 'true' : 'false'));
475 55
        $objWriter->writeAttribute('autoFilter', ($pSheet->getProtection()->getAutoFilter() ? 'true' : 'false'));
476 55
        $objWriter->writeAttribute('pivotTables', ($pSheet->getProtection()->getPivotTables() ? 'true' : 'false'));
477 55
        $objWriter->writeAttribute('selectUnlockedCells', ($pSheet->getProtection()->getSelectUnlockedCells() ? 'true' : 'false'));
478 55
        $objWriter->endElement();
479 55
    }
480
481
    /**
482
     * Write ConditionalFormatting.
483
     *
484
     * @param XMLWriter $objWriter XML Writer
485
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
486
     *
487
     * @throws WriterException
488
     */
489 55
    private function writeConditionalFormatting(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
490
    {
491
        // Conditional id
492 55
        $id = 1;
493
494
        // Loop through styles in the current worksheet
495 55
        foreach ($pSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
496 2
            foreach ($conditionalStyles as $conditional) {
497
                // WHY was this again?
498
                // 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...
499
                //    continue;
500
                // }
501 2
                if ($conditional->getConditionType() != Conditional::CONDITION_NONE) {
502
                    // conditionalFormatting
503 2
                    $objWriter->startElement('conditionalFormatting');
504 2
                    $objWriter->writeAttribute('sqref', $cellCoordinate);
505
506
                    // cfRule
507 2
                    $objWriter->startElement('cfRule');
508 2
                    $objWriter->writeAttribute('type', $conditional->getConditionType());
509 2
                    $objWriter->writeAttribute('dxfId', $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()));
510 2
                    $objWriter->writeAttribute('priority', $id++);
511
512 2
                    if (($conditional->getConditionType() == Conditional::CONDITION_CELLIS || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT)
513 2
                        && $conditional->getOperatorType() != Conditional::OPERATOR_NONE) {
514 2
                        $objWriter->writeAttribute('operator', $conditional->getOperatorType());
515
                    }
516
517 2
                    if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
518 2
                        && !is_null($conditional->getText())) {
519
                        $objWriter->writeAttribute('text', $conditional->getText());
520
                    }
521
522 2
                    if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
523 2
                        && $conditional->getOperatorType() == Conditional::OPERATOR_CONTAINSTEXT
524 2
                        && !is_null($conditional->getText())) {
525
                        $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . ')))');
526 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...
527 2
                        && $conditional->getOperatorType() == Conditional::OPERATOR_BEGINSWITH
528 2
                        && !is_null($conditional->getText())) {
529
                        $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"');
530 2
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
531 2
                        && $conditional->getOperatorType() == Conditional::OPERATOR_ENDSWITH
532 2
                        && !is_null($conditional->getText())) {
533
                        $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"');
534 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...
535 2
                        && $conditional->getOperatorType() == Conditional::OPERATOR_NOTCONTAINS
536 2
                        && !is_null($conditional->getText())) {
537
                        $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . '))');
538 2
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS
539
                        || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
540 2
                        || $conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
541 2
                        foreach ($conditional->getConditions() as $formula) {
542
                            // Formula
543 2
                            $objWriter->writeElement('formula', $formula);
544
                        }
545
                    }
546
547 2
                    $objWriter->endElement();
548
549 2
                    $objWriter->endElement();
550
                }
551
            }
552
        }
553 55
    }
554
555
    /**
556
     * Write DataValidations.
557
     *
558
     * @param XMLWriter $objWriter XML Writer
559
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
560
     *
561
     * @throws WriterException
562
     */
563 55
    private function writeDataValidations(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
564
    {
565
        // Datavalidation collection
566 55
        $dataValidationCollection = $pSheet->getDataValidationCollection();
567
568
        // Write data validations?
569 55
        if (!empty($dataValidationCollection)) {
570 2
            $objWriter->startElement('dataValidations');
571 2
            $objWriter->writeAttribute('count', count($dataValidationCollection));
572
573 2
            foreach ($dataValidationCollection as $coordinate => $dv) {
574 2
                $objWriter->startElement('dataValidation');
575
576 2
                if ($dv->getType() != '') {
577 2
                    $objWriter->writeAttribute('type', $dv->getType());
578
                }
579
580 2
                if ($dv->getErrorStyle() != '') {
581 2
                    $objWriter->writeAttribute('errorStyle', $dv->getErrorStyle());
582
                }
583
584 2
                if ($dv->getOperator() != '') {
585 2
                    $objWriter->writeAttribute('operator', $dv->getOperator());
586
                }
587
588 2
                $objWriter->writeAttribute('allowBlank', ($dv->getAllowBlank() ? '1' : '0'));
589 2
                $objWriter->writeAttribute('showDropDown', (!$dv->getShowDropDown() ? '1' : '0'));
590 2
                $objWriter->writeAttribute('showInputMessage', ($dv->getShowInputMessage() ? '1' : '0'));
591 2
                $objWriter->writeAttribute('showErrorMessage', ($dv->getShowErrorMessage() ? '1' : '0'));
592
593 2
                if ($dv->getErrorTitle() !== '') {
594 2
                    $objWriter->writeAttribute('errorTitle', $dv->getErrorTitle());
595
                }
596 2
                if ($dv->getError() !== '') {
597 2
                    $objWriter->writeAttribute('error', $dv->getError());
598
                }
599 2
                if ($dv->getPromptTitle() !== '') {
600 2
                    $objWriter->writeAttribute('promptTitle', $dv->getPromptTitle());
601
                }
602 2
                if ($dv->getPrompt() !== '') {
603 2
                    $objWriter->writeAttribute('prompt', $dv->getPrompt());
604
                }
605
606 2
                $objWriter->writeAttribute('sqref', $coordinate);
607
608 2
                if ($dv->getFormula1() !== '') {
609 2
                    $objWriter->writeElement('formula1', $dv->getFormula1());
610
                }
611 2
                if ($dv->getFormula2() !== '') {
612 1
                    $objWriter->writeElement('formula2', $dv->getFormula2());
613
                }
614
615 2
                $objWriter->endElement();
616
            }
617
618 2
            $objWriter->endElement();
619
        }
620 55
    }
621
622
    /**
623
     * Write Hyperlinks.
624
     *
625
     * @param XMLWriter $objWriter XML Writer
626
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
627
     *
628
     * @throws WriterException
629
     */
630 55
    private function writeHyperlinks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
631
    {
632
        // Hyperlink collection
633 55
        $hyperlinkCollection = $pSheet->getHyperlinkCollection();
634
635
        // Relation ID
636 55
        $relationId = 1;
637
638
        // Write hyperlinks?
639 55
        if (!empty($hyperlinkCollection)) {
640 9
            $objWriter->startElement('hyperlinks');
641
642 9
            foreach ($hyperlinkCollection as $coordinate => $hyperlink) {
643 9
                $objWriter->startElement('hyperlink');
644
645 9
                $objWriter->writeAttribute('ref', $coordinate);
646 9
                if (!$hyperlink->isInternal()) {
647 9
                    $objWriter->writeAttribute('r:id', 'rId_hyperlink_' . $relationId);
648 9
                    ++$relationId;
649
                } else {
650 7
                    $objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl()));
651
                }
652
653 9
                if ($hyperlink->getTooltip() != '') {
654 6
                    $objWriter->writeAttribute('tooltip', $hyperlink->getTooltip());
655
                }
656
657 9
                $objWriter->endElement();
658
            }
659
660 9
            $objWriter->endElement();
661
        }
662 55
    }
663
664
    /**
665
     * Write ProtectedRanges.
666
     *
667
     * @param XMLWriter $objWriter XML Writer
668
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
669
     *
670
     * @throws WriterException
671
     */
672 55
    private function writeProtectedRanges(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
673
    {
674 55
        if (count($pSheet->getProtectedCells()) > 0) {
675
            // protectedRanges
676 6
            $objWriter->startElement('protectedRanges');
677
678
            // Loop protectedRanges
679 6
            foreach ($pSheet->getProtectedCells() as $protectedCell => $passwordHash) {
680
                // protectedRange
681 6
                $objWriter->startElement('protectedRange');
682 6
                $objWriter->writeAttribute('name', 'p' . md5($protectedCell));
683 6
                $objWriter->writeAttribute('sqref', $protectedCell);
684 6
                if (!empty($passwordHash)) {
685 6
                    $objWriter->writeAttribute('password', $passwordHash);
686
                }
687 6
                $objWriter->endElement();
688
            }
689
690 6
            $objWriter->endElement();
691
        }
692 55
    }
693
694
    /**
695
     * Write MergeCells.
696
     *
697
     * @param XMLWriter $objWriter XML Writer
698
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
699
     *
700
     * @throws WriterException
701
     */
702 55
    private function writeMergeCells(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
703
    {
704 55
        if (count($pSheet->getMergeCells()) > 0) {
705
            // mergeCells
706 11
            $objWriter->startElement('mergeCells');
707
708
            // Loop mergeCells
709 11
            foreach ($pSheet->getMergeCells() as $mergeCell) {
710
                // mergeCell
711 11
                $objWriter->startElement('mergeCell');
712 11
                $objWriter->writeAttribute('ref', $mergeCell);
713 11
                $objWriter->endElement();
714
            }
715
716 11
            $objWriter->endElement();
717
        }
718 55
    }
719
720
    /**
721
     * Write PrintOptions.
722
     *
723
     * @param XMLWriter $objWriter XML Writer
724
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
725
     *
726
     * @throws WriterException
727
     */
728 55
    private function writePrintOptions(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
729
    {
730
        // printOptions
731 55
        $objWriter->startElement('printOptions');
732
733 55
        $objWriter->writeAttribute('gridLines', ($pSheet->getPrintGridlines() ? 'true' : 'false'));
734 55
        $objWriter->writeAttribute('gridLinesSet', 'true');
735
736 55
        if ($pSheet->getPageSetup()->getHorizontalCentered()) {
737
            $objWriter->writeAttribute('horizontalCentered', 'true');
738
        }
739
740 55
        if ($pSheet->getPageSetup()->getVerticalCentered()) {
741
            $objWriter->writeAttribute('verticalCentered', 'true');
742
        }
743
744 55
        $objWriter->endElement();
745 55
    }
746
747
    /**
748
     * Write PageMargins.
749
     *
750
     * @param XMLWriter $objWriter XML Writer
751
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
752
     *
753
     * @throws WriterException
754
     */
755 55
    private function writePageMargins(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
756
    {
757
        // pageMargins
758 55
        $objWriter->startElement('pageMargins');
759 55
        $objWriter->writeAttribute('left', StringHelper::formatNumber($pSheet->getPageMargins()->getLeft()));
760 55
        $objWriter->writeAttribute('right', StringHelper::formatNumber($pSheet->getPageMargins()->getRight()));
761 55
        $objWriter->writeAttribute('top', StringHelper::formatNumber($pSheet->getPageMargins()->getTop()));
762 55
        $objWriter->writeAttribute('bottom', StringHelper::formatNumber($pSheet->getPageMargins()->getBottom()));
763 55
        $objWriter->writeAttribute('header', StringHelper::formatNumber($pSheet->getPageMargins()->getHeader()));
764 55
        $objWriter->writeAttribute('footer', StringHelper::formatNumber($pSheet->getPageMargins()->getFooter()));
765 55
        $objWriter->endElement();
766 55
    }
767
768
    /**
769
     * Write AutoFilter.
770
     *
771
     * @param XMLWriter $objWriter XML Writer
772
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
773
     *
774
     * @throws WriterException
775
     */
776 55
    private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
777
    {
778 55
        $autoFilterRange = $pSheet->getAutoFilter()->getRange();
779 55
        if (!empty($autoFilterRange)) {
780
            // autoFilter
781 3
            $objWriter->startElement('autoFilter');
782
783
            // Strip any worksheet reference from the filter coordinates
784 3
            $range = Cell::splitRange($autoFilterRange);
785 3
            $range = $range[0];
786
            //    Strip any worksheet ref
787 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...
788
                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...
789
            }
790 3
            $range = implode(':', $range);
791
792 3
            $objWriter->writeAttribute('ref', str_replace('$', '', $range));
793
794 3
            $columns = $pSheet->getAutoFilter()->getColumns();
795 3
            if (count($columns > 0)) {
796 3
                foreach ($columns as $columnID => $column) {
797 2
                    $rules = $column->getRules();
798 2
                    if (count($rules) > 0) {
799 2
                        $objWriter->startElement('filterColumn');
800 2
                        $objWriter->writeAttribute('colId', $pSheet->getAutoFilter()->getColumnOffset($columnID));
801
802 2
                        $objWriter->startElement($column->getFilterType());
803 2
                        if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) {
804 1
                            $objWriter->writeAttribute('and', 1);
805
                        }
806
807 2
                        foreach ($rules as $rule) {
808 2
                            if (($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) &&
809 2
                                ($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) &&
810 2
                                ($rule->getValue() === '')) {
811
                                //    Filter rule for Blanks
812 1
                                $objWriter->writeAttribute('blank', 1);
813 2
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) {
814
                                //    Dynamic Filter Rule
815 1
                                $objWriter->writeAttribute('type', $rule->getGrouping());
816 1
                                $val = $column->getAttribute('val');
817 1
                                if ($val !== null) {
818 1
                                    $objWriter->writeAttribute('val', $val);
819
                                }
820 1
                                $maxVal = $column->getAttribute('maxVal');
821 1
                                if ($maxVal !== null) {
822 1
                                    $objWriter->writeAttribute('maxVal', $maxVal);
823
                                }
824 2
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) {
825
                                //    Top 10 Filter Rule
826
                                $objWriter->writeAttribute('val', $rule->getValue());
827
                                $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0'));
828
                                $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0'));
829
                            } else {
830
                                //    Filter, DateGroupItem or CustomFilter
831 2
                                $objWriter->startElement($rule->getRuleType());
832
833 2
                                if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) {
834 1
                                    $objWriter->writeAttribute('operator', $rule->getOperator());
835
                                }
836 2
                                if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) {
837
                                    // Date Group filters
838 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...
839 1
                                        if ($value > '') {
840 1
                                            $objWriter->writeAttribute($key, $value);
841
                                        }
842
                                    }
843 1
                                    $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping());
844
                                } else {
845 2
                                    $objWriter->writeAttribute('val', $rule->getValue());
846
                                }
847
848 2
                                $objWriter->endElement();
849
                            }
850
                        }
851
852 2
                        $objWriter->endElement();
853
854 2
                        $objWriter->endElement();
855
                    }
856
                }
857
            }
858 3
            $objWriter->endElement();
859
        }
860 55
    }
861
862
    /**
863
     * Write PageSetup.
864
     *
865
     * @param XMLWriter $objWriter XML Writer
866
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
867
     *
868
     * @throws WriterException
869
     */
870 55
    private function writePageSetup(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
871
    {
872
        // pageSetup
873 55
        $objWriter->startElement('pageSetup');
874 55
        $objWriter->writeAttribute('paperSize', $pSheet->getPageSetup()->getPaperSize());
875 55
        $objWriter->writeAttribute('orientation', $pSheet->getPageSetup()->getOrientation());
876
877 55
        if (!is_null($pSheet->getPageSetup()->getScale())) {
878 55
            $objWriter->writeAttribute('scale', $pSheet->getPageSetup()->getScale());
879
        }
880 55
        if (!is_null($pSheet->getPageSetup()->getFitToHeight())) {
881 55
            $objWriter->writeAttribute('fitToHeight', $pSheet->getPageSetup()->getFitToHeight());
882
        } else {
883
            $objWriter->writeAttribute('fitToHeight', '0');
884
        }
885 55
        if (!is_null($pSheet->getPageSetup()->getFitToWidth())) {
886 55
            $objWriter->writeAttribute('fitToWidth', $pSheet->getPageSetup()->getFitToWidth());
887
        } else {
888
            $objWriter->writeAttribute('fitToWidth', '0');
889
        }
890 55
        if (!is_null($pSheet->getPageSetup()->getFirstPageNumber())) {
891
            $objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber());
892
            $objWriter->writeAttribute('useFirstPageNumber', '1');
893
        }
894
895 55
        $objWriter->endElement();
896 55
    }
897
898
    /**
899
     * Write Header / Footer.
900
     *
901
     * @param XMLWriter $objWriter XML Writer
902
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
903
     *
904
     * @throws WriterException
905
     */
906 55
    private function writeHeaderFooter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
907
    {
908
        // headerFooter
909 55
        $objWriter->startElement('headerFooter');
910 55
        $objWriter->writeAttribute('differentOddEven', ($pSheet->getHeaderFooter()->getDifferentOddEven() ? 'true' : 'false'));
911 55
        $objWriter->writeAttribute('differentFirst', ($pSheet->getHeaderFooter()->getDifferentFirst() ? 'true' : 'false'));
912 55
        $objWriter->writeAttribute('scaleWithDoc', ($pSheet->getHeaderFooter()->getScaleWithDocument() ? 'true' : 'false'));
913 55
        $objWriter->writeAttribute('alignWithMargins', ($pSheet->getHeaderFooter()->getAlignWithMargins() ? 'true' : 'false'));
914
915 55
        $objWriter->writeElement('oddHeader', $pSheet->getHeaderFooter()->getOddHeader());
916 55
        $objWriter->writeElement('oddFooter', $pSheet->getHeaderFooter()->getOddFooter());
917 55
        $objWriter->writeElement('evenHeader', $pSheet->getHeaderFooter()->getEvenHeader());
918 55
        $objWriter->writeElement('evenFooter', $pSheet->getHeaderFooter()->getEvenFooter());
919 55
        $objWriter->writeElement('firstHeader', $pSheet->getHeaderFooter()->getFirstHeader());
920 55
        $objWriter->writeElement('firstFooter', $pSheet->getHeaderFooter()->getFirstFooter());
921 55
        $objWriter->endElement();
922 55
    }
923
924
    /**
925
     * Write Breaks.
926
     *
927
     * @param XMLWriter $objWriter XML Writer
928
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
929
     *
930
     * @throws WriterException
931
     */
932 55
    private function writeBreaks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
933
    {
934
        // Get row and column breaks
935 55
        $aRowBreaks = [];
936 55
        $aColumnBreaks = [];
937 55
        foreach ($pSheet->getBreaks() as $cell => $breakType) {
938 1
            if ($breakType == PhpspreadsheetWorksheet::BREAK_ROW) {
939 1
                $aRowBreaks[] = $cell;
940
            } elseif ($breakType == PhpspreadsheetWorksheet::BREAK_COLUMN) {
941 1
                $aColumnBreaks[] = $cell;
942
            }
943
        }
944
945
        // rowBreaks
946 55 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...
947 1
            $objWriter->startElement('rowBreaks');
948 1
            $objWriter->writeAttribute('count', count($aRowBreaks));
949 1
            $objWriter->writeAttribute('manualBreakCount', count($aRowBreaks));
950
951 1
            foreach ($aRowBreaks as $cell) {
952 1
                $coords = Cell::coordinateFromString($cell);
953
954 1
                $objWriter->startElement('brk');
955 1
                $objWriter->writeAttribute('id', $coords[1]);
956 1
                $objWriter->writeAttribute('man', '1');
957 1
                $objWriter->endElement();
958
            }
959
960 1
            $objWriter->endElement();
961
        }
962
963
        // Second, write column breaks
964 55 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...
965
            $objWriter->startElement('colBreaks');
966
            $objWriter->writeAttribute('count', count($aColumnBreaks));
967
            $objWriter->writeAttribute('manualBreakCount', count($aColumnBreaks));
968
969
            foreach ($aColumnBreaks as $cell) {
970
                $coords = Cell::coordinateFromString($cell);
971
972
                $objWriter->startElement('brk');
973
                $objWriter->writeAttribute('id', Cell::columnIndexFromString($coords[0]) - 1);
974
                $objWriter->writeAttribute('man', '1');
975
                $objWriter->endElement();
976
            }
977
978
            $objWriter->endElement();
979
        }
980 55
    }
981
982
    /**
983
     * Write SheetData.
984
     *
985
     * @param XMLWriter $objWriter XML Writer
986
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
987
     * @param string[] $pStringTable String table
988
     *
989
     * @throws WriterException
990
     */
991 55
    private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, array $pStringTable)
992
    {
993
        // Flipped stringtable, for faster index searching
994 55
        $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...
995
996
        // sheetData
997 55
        $objWriter->startElement('sheetData');
998
999
        // Get column count
1000 55
        $colCount = Cell::columnIndexFromString($pSheet->getHighestColumn());
1001
1002
        // Highest row number
1003 55
        $highestRow = $pSheet->getHighestRow();
1004
1005
        // Loop through cells
1006 55
        $cellsByRow = [];
1007 55
        foreach ($pSheet->getCoordinates() as $coordinate) {
1008 55
            $cellAddress = Cell::coordinateFromString($coordinate);
1009 55
            $cellsByRow[$cellAddress[1]][] = $coordinate;
1010
        }
1011
1012 55
        $currentRow = 0;
1013 55
        while ($currentRow++ < $highestRow) {
1014
            // Get row dimension
1015 55
            $rowDimension = $pSheet->getRowDimension($currentRow);
1016
1017
            // Write current row?
1018 55
            $writeCurrentRow = isset($cellsByRow[$currentRow]) || $rowDimension->getRowHeight() >= 0 || $rowDimension->getVisible() == false || $rowDimension->getCollapsed() == true || $rowDimension->getOutlineLevel() > 0 || $rowDimension->getXfIndex() !== null;
1019
1020 55
            if ($writeCurrentRow) {
1021
                // Start a new row
1022 55
                $objWriter->startElement('row');
1023 55
                $objWriter->writeAttribute('r', $currentRow);
1024 55
                $objWriter->writeAttribute('spans', '1:' . $colCount);
1025
1026
                // Row dimensions
1027 55
                if ($rowDimension->getRowHeight() >= 0) {
1028 5
                    $objWriter->writeAttribute('customHeight', '1');
1029 5
                    $objWriter->writeAttribute('ht', StringHelper::formatNumber($rowDimension->getRowHeight()));
1030
                }
1031
1032
                // Row visibility
1033 55
                if ($rowDimension->getVisible() == false) {
1034 2
                    $objWriter->writeAttribute('hidden', 'true');
1035
                }
1036
1037
                // Collapsed
1038 55
                if ($rowDimension->getCollapsed() == true) {
1039
                    $objWriter->writeAttribute('collapsed', 'true');
1040
                }
1041
1042
                // Outline level
1043 55
                if ($rowDimension->getOutlineLevel() > 0) {
1044
                    $objWriter->writeAttribute('outlineLevel', $rowDimension->getOutlineLevel());
1045
                }
1046
1047
                // Style
1048 55
                if ($rowDimension->getXfIndex() !== null) {
1049
                    $objWriter->writeAttribute('s', $rowDimension->getXfIndex());
1050
                    $objWriter->writeAttribute('customFormat', '1');
1051
                }
1052
1053
                // Write cells
1054 55
                if (isset($cellsByRow[$currentRow])) {
1055 55
                    foreach ($cellsByRow[$currentRow] as $cellAddress) {
1056
                        // Write cell
1057 55
                        $this->writeCell($objWriter, $pSheet, $cellAddress, $aFlippedStringTable);
1058
                    }
1059
                }
1060
1061
                // End row
1062 55
                $objWriter->endElement();
1063
            }
1064
        }
1065
1066 55
        $objWriter->endElement();
1067 55
    }
1068
1069
    /**
1070
     * Write Cell.
1071
     *
1072
     * @param XMLWriter $objWriter XML Writer
1073
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1074
     * @param Cell $pCellAddress Cell Address
1075
     * @param string[] $pStringTable String table
0 ignored issues
show
Bug introduced by
There is no parameter named $pStringTable. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1076
     * @param string[] $pFlippedStringTable String table (flipped), for faster index searching
1077
     *
1078
     * @throws WriterException
1079
     */
1080 55
    private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, $pCellAddress, array $pFlippedStringTable)
1081
    {
1082
        // Cell
1083 55
        $pCell = $pSheet->getCell($pCellAddress);
1084 55
        $objWriter->startElement('c');
1085 55
        $objWriter->writeAttribute('r', $pCellAddress);
1086
1087
        // Sheet styles
1088 55
        if ($pCell->getXfIndex() != '') {
1089 31
            $objWriter->writeAttribute('s', $pCell->getXfIndex());
1090
        }
1091
1092
        // If cell value is supplied, write cell value
1093 55
        $cellValue = $pCell->getValue();
1094 55
        if (is_object($cellValue) || $cellValue !== '') {
1095
            // Map type
1096 55
            $mappedType = $pCell->getDataType();
1097
1098
            // Write data type depending on its type
1099 55
            switch (strtolower($mappedType)) {
1100 55
                case 'inlinestr':    // Inline string
1101 54
                case 's':            // String
1102 47
                case 'b':            // Boolean
1103 50
                    $objWriter->writeAttribute('t', $mappedType);
1104 50
                    break;
1105 45
                case 'f':            // Formula
1106 18
                    $calculatedValue = ($this->getParentWriter()->getPreCalculateFormulas()) ?
1107 18
                        $pCell->getCalculatedValue() : $cellValue;
1108 18
                    if (is_string($calculatedValue)) {
1109 13
                        $objWriter->writeAttribute('t', 'str');
1110
                    }
1111 18
                    break;
1112 44
                case 'e':            // Error
1113
                    $objWriter->writeAttribute('t', $mappedType);
1114
            }
1115
1116
            // Write data depending on its type
1117 55
            switch (strtolower($mappedType)) {
1118 55
                case 'inlinestr':    // Inline string
1119 8
                    if (!$cellValue instanceof RichText) {
1120
                        $objWriter->writeElement('t', StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue)));
1121
                    } elseif ($cellValue instanceof RichText) {
1122 8
                        $objWriter->startElement('is');
1123 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...
1124 8
                        $objWriter->endElement();
1125
                    }
1126
1127 8
                    break;
1128 54
                case 's':            // String
1129 49
                    if (!$cellValue instanceof RichText) {
1130 49
                        if (isset($pFlippedStringTable[$cellValue])) {
1131 49
                            $objWriter->writeElement('v', $pFlippedStringTable[$cellValue]);
1132
                        }
1133
                    } elseif ($cellValue instanceof RichText) {
1134 2
                        $objWriter->writeElement('v', $pFlippedStringTable[$cellValue->getHashCode()]);
1135
                    }
1136
1137 49
                    break;
1138 47
                case 'f':            // Formula
1139 18
                    $attributes = $pCell->getFormulaAttributes();
1140 18
                    if ($attributes['t'] == 'array') {
1141
                        $objWriter->startElement('f');
1142
                        $objWriter->writeAttribute('t', 'array');
1143
                        $objWriter->writeAttribute('ref', $pCellAddress);
1144
                        $objWriter->writeAttribute('aca', '1');
1145
                        $objWriter->writeAttribute('ca', '1');
1146
                        $objWriter->text(substr($cellValue, 1));
1147
                        $objWriter->endElement();
1148
                    } else {
1149 18
                        $objWriter->writeElement('f', substr($cellValue, 1));
1150
                    }
1151 18
                    if ($this->getParentWriter()->getOffice2003Compatibility() === false) {
1152 18
                        if ($this->getParentWriter()->getPreCalculateFormulas()) {
1153 18
                            if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) != '#') {
1154 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...
1155
                            } else {
1156 18
                                $objWriter->writeElement('v', '0');
1157
                            }
1158
                        } else {
1159
                            $objWriter->writeElement('v', '0');
1160
                        }
1161
                    }
1162 18
                    break;
1163 46
                case 'n':            // Numeric
1164
                    // force point as decimal separator in case current locale uses comma
1165 39
                    $objWriter->writeElement('v', str_replace(',', '.', $cellValue));
1166 39
                    break;
1167 25
                case 'b':            // Boolean
1168 8
                    $objWriter->writeElement('v', ($cellValue ? '1' : '0'));
1169 8
                    break;
1170 21
                case 'e':            // Error
1171
                    if (substr($cellValue, 0, 1) == '=') {
1172
                        $objWriter->writeElement('f', substr($cellValue, 1));
1173
                        $objWriter->writeElement('v', substr($cellValue, 1));
1174
                    } else {
1175
                        $objWriter->writeElement('v', $cellValue);
1176
                    }
1177
1178
                    break;
1179
            }
1180
        }
1181
1182 55
        $objWriter->endElement();
1183 55
    }
1184
1185
    /**
1186
     * Write Drawings.
1187
     *
1188
     * @param XMLWriter $objWriter XML Writer
1189
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1190
     * @param bool $includeCharts Flag indicating if we should include drawing details for charts
1191
     *
1192
     * @throws WriterException
1193
     */
1194 55
    private function writeDrawings(XMLWriter $objWriter = null, PhpspreadsheetWorksheet $pSheet = null, $includeCharts = false)
1195
    {
1196 55
        $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...
1197
        // If sheet contains drawings, add the relationships
1198 55
        if (($pSheet->getDrawingCollection()->count() > 0) ||
1199 55
            ($chartCount > 0)) {
1200 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...
1201 22
            $objWriter->writeAttribute('r:id', 'rId1');
1202 22
            $objWriter->endElement();
1203
        }
1204 55
    }
1205
1206
    /**
1207
     * Write LegacyDrawing.
1208
     *
1209
     * @param XMLWriter $objWriter XML Writer
1210
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1211
     *
1212
     * @throws WriterException
1213
     */
1214 55
    private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
1215
    {
1216
        // If sheet contains comments, add the relationships
1217 55
        if (count($pSheet->getComments()) > 0) {
1218 9
            $objWriter->startElement('legacyDrawing');
1219 9
            $objWriter->writeAttribute('r:id', 'rId_comments_vml1');
1220 9
            $objWriter->endElement();
1221
        }
1222 55
    }
1223
1224
    /**
1225
     * Write LegacyDrawingHF.
1226
     *
1227
     * @param XMLWriter $objWriter XML Writer
1228
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
1229
     *
1230
     * @throws WriterException
1231
     */
1232 55
    private function writeLegacyDrawingHF(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
1233
    {
1234
        // If sheet contains images, add the relationships
1235 55
        if (count($pSheet->getHeaderFooter()->getImages()) > 0) {
1236 1
            $objWriter->startElement('legacyDrawingHF');
1237 1
            $objWriter->writeAttribute('r:id', 'rId_headerfooter_vml1');
1238 1
            $objWriter->endElement();
1239
        }
1240 55
    }
1241
}
1242