Completed
Push — develop ( e1f81f...539a89 )
by Adrien
16:11
created

Worksheet   F

Complexity

Total Complexity 330

Size/Duplication

Total Lines 2941
Duplicated Lines 3.57 %

Coupling/Cohesion

Components 10
Dependencies 29

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 105
loc 2941
rs 0.5217
c 1
b 0
f 0
wmc 330
lcom 10
cbo 29

148 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 30 1
A disconnectCells() 0 9 2
A __destruct() 0 6 1
A getCellCacheController() 0 4 1
A getInvalidCharacters() 0 4 1
B checkSheetCodeName() 0 20 6
A checkSheetTitle() 0 14 3
A getCellCollection() 0 11 3
A sortCellCollection() 0 7 2
A getRowDimensions() 0 4 1
A getDefaultRowDimension() 0 4 1
A getColumnDimensions() 0 4 1
A getDefaultColumnDimension() 0 4 1
A getDrawingCollection() 0 4 1
A getChartCollection() 0 4 1
A addChart() 0 12 2
A getChartCount() 0 4 1
A getChartByIndex() 0 15 4
A getChartNames() 0 8 2
A getChartByName() 0 13 4
A refreshColumnDimensions() 0 13 2
A refreshRowDimensions() 0 13 2
A calculateWorksheetDimension() 0 5 1
A calculateWorksheetDataDimension() 0 5 1
C calculateColumnWidths() 0 57 12
A getParent() 0 4 1
A rebindParent() 0 16 3
A getTitle() 0 4 1
C setTitle() 12 56 13
A getSheetState() 0 4 1
A setSheetState() 0 5 1
A getPageSetup() 0 4 1
A setPageSetup() 0 5 1
A getPageMargins() 0 4 1
A setPageMargins() 0 5 1
A getHeaderFooter() 0 4 1
A setHeaderFooter() 0 5 1
A getSheetView() 0 4 1
A setSheetView() 0 5 1
A getProtection() 0 4 1
A setProtection() 0 7 1
A getHighestColumn() 0 7 2
A getHighestDataColumn() 0 4 1
A getHighestRow() 0 7 2
A getHighestDataRow() 0 4 1
A getHighestRowAndColumn() 0 4 1
A setCellValue() 0 5 2
A setCellValueByColumnAndRow() 0 5 2
A setCellValueExplicit() 0 6 2
A setCellValueExplicitByColumnAndRow() 0 5 2
D getCell() 9 35 10
A getCellByColumnAndRow() 0 12 3
B createNewCell() 0 30 6
D cellExists() 4 41 10
A cellExistsByColumnAndRow() 0 4 1
A getRowDimension() 0 16 3
A getColumnDimension() 0 18 4
A getColumnDimensionByColumn() 0 4 1
A getStyles() 0 4 1
A getDefaultStyle() 0 4 1
A setDefaultStyle() 0 10 1
A getStyle() 0 10 1
A getConditionalStyles() 0 8 2
A conditionalStylesExists() 0 7 2
A removeConditionalStyles() 0 5 1
A getConditionalStylesCollection() 0 4 1
A setConditionalStyles() 0 5 1
A getStyleByColumnAndRow() 0 9 3
A setSharedStyle() 0 5 1
C duplicateStyle() 10 35 7
C duplicateConditionalStyle() 10 27 7
A duplicateStyleArray() 0 5 1
A setBreak() 0 19 4
A setBreakByColumnAndRow() 0 4 1
A getBreaks() 0 4 1
B mergeCells() 0 32 5
A mergeCellsByColumnAndRow() 0 5 1
A unmergeCells() 0 17 3
A unmergeCellsByColumnAndRow() 0 5 1
A getMergeCells() 0 4 1
A setMergeCells() 0 5 1
A protectCells() 0 12 2
A protectCellsByColumnAndRow() 0 5 1
A unprotectCells() 0 12 2
A unprotectCellsByColumnAndRow() 0 5 1
A getProtectedCells() 0 4 1
A getAutoFilter() 0 4 1
A setAutoFilter() 0 10 4
A setAutoFilterByColumnAndRow() 0 8 1
A removeAutoFilter() 0 5 1
A getFreezePane() 0 4 1
A freezePane() 0 11 3
A freezePaneByColumnAndRow() 0 4 1
A unfreezePane() 0 4 1
A insertNewRowBefore() 10 10 2
A insertNewColumnBefore() 10 10 2
A insertNewColumnBeforeByIndex() 0 8 2
A removeRow() 0 15 3
A removeColumn() 0 16 3
A removeColumnByIndex() 0 8 2
A getShowGridlines() 0 4 1
A setShowGridlines() 0 5 1
A getPrintGridlines() 0 4 1
A setPrintGridlines() 0 5 1
A getShowRowColHeaders() 0 4 1
A setShowRowColHeaders() 0 5 1
A getShowSummaryBelow() 0 4 1
A setShowSummaryBelow() 0 5 1
A getShowSummaryRight() 0 4 1
A setShowSummaryRight() 0 5 1
A getComments() 0 4 1
A setComments() 0 6 1
B getComment() 0 23 6
A getCommentByColumnAndRow() 0 4 1
A getSelectedCell() 0 4 1
A getActiveCell() 0 4 1
A getSelectedCells() 0 4 1
A setSelectedCell() 0 4 1
B setSelectedCells() 0 26 3
A setSelectedCellByColumnAndRow() 0 4 1
A getRightToLeft() 0 4 1
A setRightToLeft() 0 5 1
C fromArray() 0 35 8
C rangeToArray() 0 57 12
A namedRangeToArray() 0 12 2
A toArray() 0 11 1
A getRowIterator() 0 4 1
A getColumnIterator() 0 4 1
B garbageCollect() 0 39 4
A getHashCode() 0 8 3
A extractSheetTitle() 0 13 3
A getHyperlink() 11 11 2
A setHyperlink() 0 9 2
A hyperlinkExists() 0 4 1
A getHyperlinkCollection() 0 4 1
A getDataValidation() 11 11 2
A setDataValidation() 0 9 2
A dataValidationExists() 0 4 1
A getDataValidationCollection() 0 4 1
B shrinkRangeToFit() 6 29 6
A getTabColor() 0 7 2
A resetTabColor() 0 7 1
A isTabColorSet() 0 4 1
A copy() 0 6 1
D __clone() 0 25 9
D setCodeName() 12 44 10
A getCodeName() 0 4 1
A hasCodeName() 0 4 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Worksheet often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Worksheet, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpSpreadsheet;
4
5
/**
6
 * PhpSpreadsheet\Worksheet
7
 *
8
 * Copyright (c) 2006 - 2016 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
 * @copyright  Copyright (c) 2006 - 2016 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
26
 * @license    http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt    LGPL
27
 * @version    ##VERSION##, ##DATE##
28
 */
29
class Worksheet implements IComparable
30
{
31
    /* Break types */
32
    const BREAK_NONE   = 0;
33
    const BREAK_ROW    = 1;
34
    const BREAK_COLUMN = 2;
35
36
    /* Sheet state */
37
    const SHEETSTATE_VISIBLE    = 'visible';
38
    const SHEETSTATE_HIDDEN     = 'hidden';
39
    const SHEETSTATE_VERYHIDDEN = 'veryHidden';
40
41
    /**
42
     * Invalid characters in sheet title
43
     *
44
     * @var array
45
     */
46
    private static $invalidCharacters = array('*', ':', '/', '\\', '?', '[', ']');
47
48
    /**
49
     * Parent spreadsheet
50
     *
51
     * @var Spreadsheet
52
     */
53
    private $parent;
54
55
    /**
56
     * Cacheable collection of cells
57
     *
58
     * @var CachedObjectStorage_xxx
59
     */
60
    private $cellCollection;
61
62
    /**
63
     * Collection of row dimensions
64
     *
65
     * @var Worksheet\RowDimension[]
66
     */
67
    private $rowDimensions = array();
68
69
    /**
70
     * Default row dimension
71
     *
72
     * @var Worksheet\RowDimension
73
     */
74
    private $defaultRowDimension;
75
76
    /**
77
     * Collection of column dimensions
78
     *
79
     * @var Worksheet\ColumnDimension[]
80
     */
81
    private $columnDimensions = array();
82
83
    /**
84
     * Default column dimension
85
     *
86
     * @var Worksheet\ColumnDimension
87
     */
88
    private $defaultColumnDimension = null;
89
90
    /**
91
     * Collection of drawings
92
     *
93
     * @var Worksheet\BaseDrawing[]
94
     */
95
    private $drawingCollection = null;
96
97
    /**
98
     * Collection of Chart objects
99
     *
100
     * @var Chart[]
101
     */
102
    private $chartCollection = array();
103
104
    /**
105
     * Worksheet title
106
     *
107
     * @var string
108
     */
109
    private $title;
110
111
    /**
112
     * Sheet state
113
     *
114
     * @var string
115
     */
116
    private $sheetState;
117
118
    /**
119
     * Page setup
120
     *
121
     * @var Worksheet\PageSetup
122
     */
123
    private $pageSetup;
124
125
    /**
126
     * Page margins
127
     *
128
     * @var Worksheet\PageMargins
129
     */
130
    private $pageMargins;
131
132
    /**
133
     * Page header/footer
134
     *
135
     * @var Worksheet\HeaderFooter
136
     */
137
    private $headerFooter;
138
139
    /**
140
     * Sheet view
141
     *
142
     * @var Worksheet\SheetView
143
     */
144
    private $sheetView;
145
146
    /**
147
     * Protection
148
     *
149
     * @var Worksheet\Protection
150
     */
151
    private $protection;
152
153
    /**
154
     * Collection of styles
155
     *
156
     * @var Style[]
157
     */
158
    private $styles = array();
159
160
    /**
161
     * Conditional styles. Indexed by cell coordinate, e.g. 'A1'
162
     *
163
     * @var array
164
     */
165
    private $conditionalStylesCollection = array();
166
167
    /**
168
     * Is the current cell collection sorted already?
169
     *
170
     * @var boolean
171
     */
172
    private $cellCollectionIsSorted = false;
173
174
    /**
175
     * Collection of breaks
176
     *
177
     * @var array
178
     */
179
    private $breaks = array();
180
181
    /**
182
     * Collection of merged cell ranges
183
     *
184
     * @var array
185
     */
186
    private $mergeCells = array();
187
188
    /**
189
     * Collection of protected cell ranges
190
     *
191
     * @var array
192
     */
193
    private $protectedCells = array();
194
195
    /**
196
     * Autofilter Range and selection
197
     *
198
     * @var Worksheet\AutoFilter
199
     */
200
    private $autoFilter;
201
202
    /**
203
     * Freeze pane
204
     *
205
     * @var string
206
     */
207
    private $freezePane = '';
208
209
    /**
210
     * Show gridlines?
211
     *
212
     * @var boolean
213
     */
214
    private $showGridlines = true;
215
216
    /**
217
    * Print gridlines?
218
    *
219
    * @var boolean
220
    */
221
    private $printGridlines = false;
222
223
    /**
224
    * Show row and column headers?
225
    *
226
    * @var boolean
227
    */
228
    private $showRowColHeaders = true;
229
230
    /**
231
     * Show summary below? (Row/Column outline)
232
     *
233
     * @var boolean
234
     */
235
    private $showSummaryBelow = true;
236
237
    /**
238
     * Show summary right? (Row/Column outline)
239
     *
240
     * @var boolean
241
     */
242
    private $showSummaryRight = true;
243
244
    /**
245
     * Collection of comments
246
     *
247
     * @var Comment[]
248
     */
249
    private $comments = array();
250
251
    /**
252
     * Active cell. (Only one!)
253
     *
254
     * @var string
255
     */
256
    private $activeCell = 'A1';
257
258
    /**
259
     * Selected cells
260
     *
261
     * @var string
262
     */
263
    private $selectedCells = 'A1';
264
265
    /**
266
     * Cached highest column
267
     *
268
     * @var string
269
     */
270
    private $cachedHighestColumn = 'A';
271
272
    /**
273
     * Cached highest row
274
     *
275
     * @var int
276
     */
277
    private $cachedHighestRow = 1;
278
279
    /**
280
     * Right-to-left?
281
     *
282
     * @var boolean
283
     */
284
    private $rightToLeft = false;
285
286
    /**
287
     * Hyperlinks. Indexed by cell coordinate, e.g. 'A1'
288
     *
289
     * @var array
290
     */
291
    private $hyperlinkCollection = array();
292
293
    /**
294
     * Data validation objects. Indexed by cell coordinate, e.g. 'A1'
295
     *
296
     * @var array
297
     */
298
    private $dataValidationCollection = array();
299
300
    /**
301
     * Tab color
302
     *
303
     * @var Style\Color
304
     */
305
    private $tabColor;
306
307
    /**
308
     * Dirty flag
309
     *
310
     * @var boolean
311
     */
312
    private $dirty = true;
313
314
    /**
315
     * Hash
316
     *
317
     * @var string
318
     */
319
    private $hash;
320
321
    /**
322
    * CodeName
323
    *
324
    * @var string
325
    */
326
    private $codeName = null;
327
328
    /**
329
     * Create a new worksheet
330
     *
331
     * @param Spreadsheet        $Parent
0 ignored issues
show
Documentation introduced by
There is no parameter named $Parent. Did you maybe mean $parent?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

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

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

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

Loading history...
332
     * @param string        $pTitle
333
     */
334
    public function __construct(Spreadsheet $parent = null, $pTitle = 'Worksheet')
335
    {
336
        // Set parent and title
337
        $this->parent = $parent;
338
        $this->setTitle($pTitle, false);
339
        // setTitle can change $pTitle
340
        $this->setCodeName($this->getTitle());
341
        $this->setSheetState(Worksheet::SHEETSTATE_VISIBLE);
342
343
        $this->cellCollection         = CachedObjectStorageFactory::getInstance($this);
0 ignored issues
show
Documentation Bug introduced by
It seems like \PhpSpreadsheet\CachedOb...ory::getInstance($this) of type object<PhpSpreadsheet\CachedObjectStorage\ICache> is incompatible with the declared type object<PhpSpreadsheet\CachedObjectStorage_xxx> of property $cellCollection.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
344
        // Set page setup
345
        $this->pageSetup              = new Worksheet\PageSetup();
346
        // Set page margins
347
        $this->pageMargins            = new Worksheet\PageMargins();
348
        // Set page header/footer
349
        $this->headerFooter           = new Worksheet\HeaderFooter();
350
        // Set sheet view
351
        $this->sheetView              = new Worksheet\SheetView();
352
        // Drawing collection
353
        $this->drawingCollection      = new \ArrayObject();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \ArrayObject() of type object<ArrayObject> is incompatible with the declared type array<integer,object<Php...Worksheet\BaseDrawing>> of property $drawingCollection.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
354
        // Chart collection
355
        $this->chartCollection        = new \ArrayObject();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \ArrayObject() of type object<ArrayObject> is incompatible with the declared type array<integer,object<PhpSpreadsheet\Chart>> of property $chartCollection.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
356
        // Protection
357
        $this->protection             = new Worksheet\Protection();
358
        // Default row dimension
359
        $this->defaultRowDimension    = new Worksheet\RowDimension(null);
360
        // Default column dimension
361
        $this->defaultColumnDimension = new Worksheet\ColumnDimension(null);
362
        $this->autoFilter             = new Worksheet\AutoFilter(null, $this);
363
    }
364
365
366
    /**
367
     * Disconnect all cells from this Worksheet object,
368
     *    typically so that the worksheet object can be unset
369
     *
370
     */
371
    public function disconnectCells()
372
    {
373
        if ($this->cellCollection !== null) {
374
            $this->cellCollection->unsetWorksheetCells();
375
            $this->cellCollection = null;
376
        }
377
        //    detach ourself from the workbook, so that it can then delete this worksheet successfully
378
        $this->parent = null;
379
    }
380
381
    /**
382
     * Code to execute when this worksheet is unset()
383
     *
384
     */
385
    public function __destruct()
386
    {
387
        Calculation::getInstance($this->parent)->clearCalculationCacheForWorksheet($this->title);
388
389
        $this->disconnectCells();
390
    }
391
392
   /**
393
     * Return the cache controller for the cell collection
394
     *
395
     * @return CachedObjectStorage_xxx
396
     */
397
    public function getCellCacheController()
398
    {
399
        return $this->cellCollection;
400
    }
401
402
403
    /**
404
     * Get array of invalid characters for sheet title
405
     *
406
     * @return array
407
     */
408
    public static function getInvalidCharacters()
409
    {
410
        return self::$invalidCharacters;
411
    }
412
413
    /**
414
     * Check sheet code name for valid Excel syntax
415
     *
416
     * @param string $pValue The string to check
417
     * @return string The valid string
418
     * @throws Exception
419
     */
420
    private static function checkSheetCodeName($pValue)
421
    {
422
        $CharCount = Shared\StringHelper::countCharacters($pValue);
423
        if ($CharCount == 0) {
424
            throw new Exception('Sheet code name cannot be empty.');
425
        }
426
        // Some of the printable ASCII characters are invalid:  * : / \ ? [ ] and  first and last characters cannot be a "'"
427
        if ((str_replace(self::$invalidCharacters, '', $pValue) !== $pValue) ||
428
            (Shared\StringHelper::substring($pValue, -1, 1)=='\'') ||
429
            (Shared\StringHelper::substring($pValue, 0, 1)=='\'')) {
430
            throw new Exception('Invalid character found in sheet code name');
431
        }
432
433
        // Maximum 31 characters allowed for sheet title
434
        if ($CharCount > 31) {
435
            throw new Exception('Maximum 31 characters allowed in sheet code name.');
436
        }
437
438
        return $pValue;
439
    }
440
441
   /**
442
     * Check sheet title for valid Excel syntax
443
     *
444
     * @param string $pValue The string to check
445
     * @return string The valid string
446
     * @throws Exception
447
     */
448
    private static function checkSheetTitle($pValue)
449
    {
450
        // Some of the printable ASCII characters are invalid:  * : / \ ? [ ]
451
        if (str_replace(self::$invalidCharacters, '', $pValue) !== $pValue) {
452
            throw new Exception('Invalid character found in sheet title');
453
        }
454
455
        // Maximum 31 characters allowed for sheet title
456
        if (Shared\StringHelper::countCharacters($pValue) > 31) {
457
            throw new Exception('Maximum 31 characters allowed in sheet title.');
458
        }
459
460
        return $pValue;
461
    }
462
463
    /**
464
     * Get collection of cells
465
     *
466
     * @param boolean $pSorted Also sort the cell collection?
467
     * @return Cell[]
468
     */
469
    public function getCellCollection($pSorted = true)
470
    {
471
        if ($pSorted) {
472
            // Re-order cell collection
473
            return $this->sortCellCollection();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->sortCellCollection(); (PhpSpreadsheet\Worksheet) is incompatible with the return type documented by PhpSpreadsheet\Worksheet::getCellCollection of type PhpSpreadsheet\Cell[].

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
474
        }
475
        if ($this->cellCollection !== null) {
476
            return $this->cellCollection->getCellList();
477
        }
478
        return array();
479
    }
480
481
    /**
482
     * Sort collection of cells
483
     *
484
     * @return Worksheet
485
     */
486
    public function sortCellCollection()
487
    {
488
        if ($this->cellCollection !== null) {
489
            return $this->cellCollection->getSortedCellList();
490
        }
491
        return array();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return array(); (array) is incompatible with the return type documented by PhpSpreadsheet\Worksheet::sortCellCollection of type PhpSpreadsheet\Worksheet.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
492
    }
493
494
    /**
495
     * Get collection of row dimensions
496
     *
497
     * @return Worksheet\RowDimension[]
498
     */
499
    public function getRowDimensions()
500
    {
501
        return $this->rowDimensions;
502
    }
503
504
    /**
505
     * Get default row dimension
506
     *
507
     * @return Worksheet\RowDimension
508
     */
509
    public function getDefaultRowDimension()
510
    {
511
        return $this->defaultRowDimension;
512
    }
513
514
    /**
515
     * Get collection of column dimensions
516
     *
517
     * @return Worksheet\ColumnDimension[]
518
     */
519
    public function getColumnDimensions()
520
    {
521
        return $this->columnDimensions;
522
    }
523
524
    /**
525
     * Get default column dimension
526
     *
527
     * @return Worksheet\ColumnDimension
528
     */
529
    public function getDefaultColumnDimension()
530
    {
531
        return $this->defaultColumnDimension;
532
    }
533
534
    /**
535
     * Get collection of drawings
536
     *
537
     * @return Worksheet\BaseDrawing[]
538
     */
539
    public function getDrawingCollection()
540
    {
541
        return $this->drawingCollection;
542
    }
543
544
    /**
545
     * Get collection of charts
546
     *
547
     * @return Chart[]
548
     */
549
    public function getChartCollection()
550
    {
551
        return $this->chartCollection;
552
    }
553
554
    /**
555
     * Add chart
556
     *
557
     * @param Chart $pChart
558
     * @param int|null $iChartIndex Index where chart should go (0,1,..., or null for last)
559
     * @return Chart
560
     */
561
    public function addChart(Chart $pChart = null, $iChartIndex = null)
562
    {
563
        $pChart->setWorksheet($this);
0 ignored issues
show
Bug introduced by
It seems like $pChart 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...
564
        if (is_null($iChartIndex)) {
565
            $this->chartCollection[] = $pChart;
566
        } else {
567
            // Insert the chart at the requested index
568
            array_splice($this->chartCollection, $iChartIndex, 0, array($pChart));
569
        }
570
571
        return $pChart;
572
    }
573
574
    /**
575
     * Return the count of charts on this worksheet
576
     *
577
     * @return int        The number of charts
578
     */
579
    public function getChartCount()
580
    {
581
        return count($this->chartCollection);
582
    }
583
584
    /**
585
     * Get a chart by its index position
586
     *
587
     * @param string $index Chart index position
588
     * @return false|Chart
589
     * @throws Exception
590
     */
591
    public function getChartByIndex($index = null)
592
    {
593
        $chartCount = count($this->chartCollection);
594
        if ($chartCount == 0) {
595
            return false;
596
        }
597
        if (is_null($index)) {
598
            $index = --$chartCount;
599
        }
600
        if (!isset($this->chartCollection[$index])) {
601
            return false;
602
        }
603
604
        return $this->chartCollection[$index];
605
    }
606
607
    /**
608
     * Return an array of the names of charts on this worksheet
609
     *
610
     * @return string[] The names of charts
611
     * @throws Exception
612
     */
613
    public function getChartNames()
614
    {
615
        $chartNames = array();
616
        foreach ($this->chartCollection as $chart) {
617
            $chartNames[] = $chart->getName();
618
        }
619
        return $chartNames;
620
    }
621
622
    /**
623
     * Get a chart by name
624
     *
625
     * @param string $chartName Chart name
626
     * @return false|Chart
627
     * @throws Exception
628
     */
629
    public function getChartByName($chartName = '')
630
    {
631
        $chartCount = count($this->chartCollection);
632
        if ($chartCount == 0) {
633
            return false;
634
        }
635
        foreach ($this->chartCollection as $index => $chart) {
636
            if ($chart->getName() == $chartName) {
637
                return $this->chartCollection[$index];
638
            }
639
        }
640
        return false;
641
    }
642
643
    /**
644
     * Refresh column dimensions
645
     *
646
     * @return Worksheet
647
     */
648
    public function refreshColumnDimensions()
649
    {
650
        $currentColumnDimensions = $this->getColumnDimensions();
651
        $newColumnDimensions = array();
652
653
        foreach ($currentColumnDimensions as $objColumnDimension) {
654
            $newColumnDimensions[$objColumnDimension->getColumnIndex()] = $objColumnDimension;
655
        }
656
657
        $this->columnDimensions = $newColumnDimensions;
658
659
        return $this;
660
    }
661
662
    /**
663
     * Refresh row dimensions
664
     *
665
     * @return Worksheet
666
     */
667
    public function refreshRowDimensions()
668
    {
669
        $currentRowDimensions = $this->getRowDimensions();
670
        $newRowDimensions = array();
671
672
        foreach ($currentRowDimensions as $objRowDimension) {
673
            $newRowDimensions[$objRowDimension->getRowIndex()] = $objRowDimension;
674
        }
675
676
        $this->rowDimensions = $newRowDimensions;
677
678
        return $this;
679
    }
680
681
    /**
682
     * Calculate worksheet dimension
683
     *
684
     * @return string  String containing the dimension of this worksheet
685
     */
686
    public function calculateWorksheetDimension()
687
    {
688
        // Return
689
        return 'A1' . ':' .  $this->getHighestColumn() . $this->getHighestRow();
690
    }
691
692
    /**
693
     * Calculate worksheet data dimension
694
     *
695
     * @return string  String containing the dimension of this worksheet that actually contain data
696
     */
697
    public function calculateWorksheetDataDimension()
698
    {
699
        // Return
700
        return 'A1' . ':' .  $this->getHighestDataColumn() . $this->getHighestDataRow();
701
    }
702
703
    /**
704
     * Calculate widths for auto-size columns
705
     *
706
     * @param  boolean  $calculateMergeCells  Calculate merge cell width
707
     * @return Worksheet;
0 ignored issues
show
Documentation introduced by
The doc-type Worksheet; could not be parsed: Expected "|" or "end of type", but got ";" at position 9. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
708
     */
709
    public function calculateColumnWidths($calculateMergeCells = false)
0 ignored issues
show
Unused Code introduced by
The parameter $calculateMergeCells is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
710
    {
711
        // initialize $autoSizes array
712
        $autoSizes = array();
713
        foreach ($this->getColumnDimensions() as $colDimension) {
714
            if ($colDimension->getAutoSize()) {
715
                $autoSizes[$colDimension->getColumnIndex()] = -1;
716
            }
717
        }
718
719
        // There is only something to do if there are some auto-size columns
720
        if (!empty($autoSizes)) {
721
            // build list of cells references that participate in a merge
722
            $isMergeCell = array();
723
            foreach ($this->getMergeCells() as $cells) {
724
                foreach (Cell::extractAllCellReferencesInRange($cells) as $cellReference) {
0 ignored issues
show
Documentation introduced by
$cells is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
725
                    $isMergeCell[$cellReference] = true;
726
                }
727
            }
728
729
            // loop through all cells in the worksheet
730
            foreach ($this->getCellCollection(false) as $cellID) {
731
                $cell = $this->getCell($cellID, false);
732
                if ($cell !== null && isset($autoSizes[$this->cellCollection->getCurrentColumn()])) {
733
                    // Determine width if cell does not participate in a merge
734
                    if (!isset($isMergeCell[$this->cellCollection->getCurrentAddress()])) {
735
                        // Calculated value
736
                        // To formatted string
737
                        $cellValue = Style\NumberFormat::toFormattedString(
738
                            $cell->getCalculatedValue(),
739
                            $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode()
740
                        );
741
742
                        $autoSizes[$this->cellCollection->getCurrentColumn()] = max(
743
                            (float) $autoSizes[$this->cellCollection->getCurrentColumn()],
744
                            (float) Shared\Font::calculateColumnWidth(
745
                                $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont(),
746
                                $cellValue,
747
                                $this->getParent()->getCellXfByIndex($cell->getXfIndex())->getAlignment()->getTextRotation(),
748
                                $this->getDefaultStyle()->getFont()
0 ignored issues
show
Deprecated Code introduced by
The method PhpSpreadsheet\Worksheet::getDefaultStyle() has been deprecated.

This method has been deprecated.

Loading history...
749
                            )
750
                        );
751
                    }
752
                }
753
            }
754
755
            // adjust column widths
756
            foreach ($autoSizes as $columnIndex => $width) {
757
                if ($width == -1) {
758
                    $width = $this->getDefaultColumnDimension()->getWidth();
759
                }
760
                $this->getColumnDimension($columnIndex)->setWidth($width);
761
            }
762
        }
763
764
        return $this;
765
    }
766
767
    /**
768
     * Get parent
769
     *
770
     * @return PhpSpreadsheet
771
     */
772
    public function getParent()
773
    {
774
        return $this->parent;
775
    }
776
777
    /**
778
     * Re-bind parent
779
     *
780
     * @param Spreadsheet $parent
781
     * @return Worksheet
782
     */
783
    public function rebindParent(Spreadsheet $parent)
784
    {
785
        if ($this->parent !== null) {
786
            $namedRanges = $this->parent->getNamedRanges();
787
            foreach ($namedRanges as $namedRange) {
788
                $parent->addNamedRange($namedRange);
789
            }
790
791
            $this->parent->removeSheetByIndex(
792
                $this->parent->getIndex($this)
793
            );
794
        }
795
        $this->parent = $parent;
796
797
        return $this;
798
    }
799
800
    /**
801
     * Get title
802
     *
803
     * @return string
804
     */
805
    public function getTitle()
806
    {
807
        return $this->title;
808
    }
809
810
    /**
811
     * Set title
812
     *
813
     * @param string $pValue String containing the dimension of this worksheet
814
     * @param string $updateFormulaCellReferences boolean Flag indicating whether cell references in formulae should
815
     *            be updated to reflect the new sheet name.
816
     *          This should be left as the default true, unless you are
817
     *          certain that no formula cells on any worksheet contain
818
     *          references to this worksheet
819
     * @return Worksheet
820
     */
821
    public function setTitle($pValue = 'Worksheet', $updateFormulaCellReferences = true)
822
    {
823
        // Is this a 'rename' or not?
824
        if ($this->getTitle() == $pValue) {
825
            return $this;
826
        }
827
828
        // Syntax check
829
        self::checkSheetTitle($pValue);
830
831
        // Old title
832
        $oldTitle = $this->getTitle();
833
834
        if ($this->parent) {
835
            // Is there already such sheet name?
836
            if ($this->parent->sheetNameExists($pValue)) {
837
                // Use name, but append with lowest possible integer
838
839
                if (Shared\StringHelper::countCharacters($pValue) > 29) {
840
                    $pValue = Shared\StringHelper::substring($pValue, 0, 29);
841
                }
842
                $i = 1;
843 View Code Duplication
                while ($this->parent->sheetNameExists($pValue . ' ' . $i)) {
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...
844
                    ++$i;
845
                    if ($i == 10) {
846
                        if (Shared\StringHelper::countCharacters($pValue) > 28) {
847
                            $pValue = Shared\StringHelper::substring($pValue, 0, 28);
848
                        }
849
                    } elseif ($i == 100) {
850
                        if (Shared\StringHelper::countCharacters($pValue) > 27) {
851
                            $pValue = Shared\StringHelper::substring($pValue, 0, 27);
852
                        }
853
                    }
854
                }
855
856
                $altTitle = $pValue . ' ' . $i;
857
                return $this->setTitle($altTitle, $updateFormulaCellReferences);
858
            }
859
        }
860
861
        // Set title
862
        $this->title = $pValue;
863
        $this->dirty = true;
864
865
        if ($this->parent && $this->parent->getCalculationEngine()) {
866
            // New title
867
            $newTitle = $this->getTitle();
868
            $this->parent->getCalculationEngine()
869
                ->renameCalculationCacheForWorksheet($oldTitle, $newTitle);
870
            if ($updateFormulaCellReferences) {
871
                ReferenceHelper::getInstance()->updateNamedFormulas($this->parent, $oldTitle, $newTitle);
872
            }
873
        }
874
875
        return $this;
876
    }
877
878
    /**
879
     * Get sheet state
880
     *
881
     * @return string Sheet state (visible, hidden, veryHidden)
882
     */
883
    public function getSheetState()
884
    {
885
        return $this->sheetState;
886
    }
887
888
    /**
889
     * Set sheet state
890
     *
891
     * @param string $value Sheet state (visible, hidden, veryHidden)
892
     * @return Worksheet
893
     */
894
    public function setSheetState($value = Worksheet::SHEETSTATE_VISIBLE)
895
    {
896
        $this->sheetState = $value;
897
        return $this;
898
    }
899
900
    /**
901
     * Get page setup
902
     *
903
     * @return Worksheet\PageSetup
904
     */
905
    public function getPageSetup()
906
    {
907
        return $this->pageSetup;
908
    }
909
910
    /**
911
     * Set page setup
912
     *
913
     * @param Worksheet\PageSetup    $pValue
914
     * @return Worksheet
915
     */
916
    public function setPageSetup(Worksheet\PageSetup $pValue)
917
    {
918
        $this->pageSetup = $pValue;
919
        return $this;
920
    }
921
922
    /**
923
     * Get page margins
924
     *
925
     * @return Worksheet\PageMargins
926
     */
927
    public function getPageMargins()
928
    {
929
        return $this->pageMargins;
930
    }
931
932
    /**
933
     * Set page margins
934
     *
935
     * @param Worksheet\PageMargins    $pValue
936
     * @return Worksheet
937
     */
938
    public function setPageMargins(Worksheet\PageMargins $pValue)
939
    {
940
        $this->pageMargins = $pValue;
941
        return $this;
942
    }
943
944
    /**
945
     * Get page header/footer
946
     *
947
     * @return Worksheet\HeaderFooter
948
     */
949
    public function getHeaderFooter()
950
    {
951
        return $this->headerFooter;
952
    }
953
954
    /**
955
     * Set page header/footer
956
     *
957
     * @param Worksheet\HeaderFooter    $pValue
958
     * @return Worksheet
959
     */
960
    public function setHeaderFooter(Worksheet\HeaderFooter $pValue)
961
    {
962
        $this->headerFooter = $pValue;
963
        return $this;
964
    }
965
966
    /**
967
     * Get sheet view
968
     *
969
     * @return Worksheet\SheetView
970
     */
971
    public function getSheetView()
972
    {
973
        return $this->sheetView;
974
    }
975
976
    /**
977
     * Set sheet view
978
     *
979
     * @param Worksheet\SheetView    $pValue
980
     * @return Worksheet
981
     */
982
    public function setSheetView(Worksheet\SheetView $pValue)
983
    {
984
        $this->sheetView = $pValue;
985
        return $this;
986
    }
987
988
    /**
989
     * Get Protection
990
     *
991
     * @return Worksheet\Protection
992
     */
993
    public function getProtection()
994
    {
995
        return $this->protection;
996
    }
997
998
    /**
999
     * Set Protection
1000
     *
1001
     * @param Worksheet\Protection    $pValue
1002
     * @return Worksheet
1003
     */
1004
    public function setProtection(Worksheet\Protection $pValue)
1005
    {
1006
        $this->protection = $pValue;
1007
        $this->dirty = true;
1008
1009
        return $this;
1010
    }
1011
1012
    /**
1013
     * Get highest worksheet column
1014
     *
1015
     * @param   string     $row        Return the data highest column for the specified row,
1016
     *                                     or the highest column of any row if no row number is passed
1017
     * @return string Highest column name
1018
     */
1019
    public function getHighestColumn($row = null)
1020
    {
1021
        if ($row == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $row of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1022
            return $this->cachedHighestColumn;
1023
        }
1024
        return $this->getHighestDataColumn($row);
1025
    }
1026
1027
    /**
1028
     * Get highest worksheet column that contains data
1029
     *
1030
     * @param   string     $row        Return the highest data column for the specified row,
1031
     *                                     or the highest data column of any row if no row number is passed
1032
     * @return string Highest column name that contains data
1033
     */
1034
    public function getHighestDataColumn($row = null)
1035
    {
1036
        return $this->cellCollection->getHighestColumn($row);
1037
    }
1038
1039
    /**
1040
     * Get highest worksheet row
1041
     *
1042
     * @param   string     $column     Return the highest data row for the specified column,
1043
     *                                     or the highest row of any column if no column letter is passed
1044
     * @return int Highest row number
1045
     */
1046
    public function getHighestRow($column = null)
1047
    {
1048
        if ($column == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $column of type string|null against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1049
            return $this->cachedHighestRow;
1050
        }
1051
        return $this->getHighestDataRow($column);
1052
    }
1053
1054
    /**
1055
     * Get highest worksheet row that contains data
1056
     *
1057
     * @param   string     $column     Return the highest data row for the specified column,
1058
     *                                     or the highest data row of any column if no column letter is passed
1059
     * @return string Highest row number that contains data
1060
     */
1061
    public function getHighestDataRow($column = null)
1062
    {
1063
        return $this->cellCollection->getHighestRow($column);
1064
    }
1065
1066
    /**
1067
     * Get highest worksheet column and highest row that have cell records
1068
     *
1069
     * @return array Highest column name and highest row number
1070
     */
1071
    public function getHighestRowAndColumn()
1072
    {
1073
        return $this->cellCollection->getHighestRowAndColumn();
1074
    }
1075
1076
    /**
1077
     * Set a cell value
1078
     *
1079
     * @param string $pCoordinate Coordinate of the cell
1080
     * @param mixed $pValue Value of the cell
1081
     * @param bool $returnCell   Return the worksheet (false, default) or the cell (true)
1082
     * @return Worksheet|Cell    Depending on the last parameter being specified
1083
     */
1084
    public function setCellValue($pCoordinate = 'A1', $pValue = null, $returnCell = false)
1085
    {
1086
        $cell = $this->getCell(strtoupper($pCoordinate))->setValue($pValue);
1087
        return ($returnCell) ? $cell : $this;
1088
    }
1089
1090
    /**
1091
     * Set a cell value by using numeric cell coordinates
1092
     *
1093
     * @param string $pColumn Numeric column coordinate of the cell (A = 0)
1094
     * @param string $pRow Numeric row coordinate of the cell
1095
     * @param mixed $pValue Value of the cell
1096
     * @param bool $returnCell Return the worksheet (false, default) or the cell (true)
1097
     * @return Worksheet|Cell    Depending on the last parameter being specified
1098
     */
1099
    public function setCellValueByColumnAndRow($pColumn = 0, $pRow = 1, $pValue = null, $returnCell = false)
1100
    {
1101
        $cell = $this->getCellByColumnAndRow($pColumn, $pRow)->setValue($pValue);
1102
        return ($returnCell) ? $cell : $this;
1103
    }
1104
1105
    /**
1106
     * Set a cell value
1107
     *
1108
     * @param string $pCoordinate Coordinate of the cell
1109
     * @param mixed  $pValue Value of the cell
1110
     * @param string $pDataType Explicit data type
1111
     * @param bool $returnCell Return the worksheet (false, default) or the cell (true)
1112
     * @return Worksheet|Cell    Depending on the last parameter being specified
1113
     */
1114
    public function setCellValueExplicit($pCoordinate = 'A1', $pValue = null, $pDataType = Cell\DataType::TYPE_STRING, $returnCell = false)
1115
    {
1116
        // Set value
1117
        $cell = $this->getCell(strtoupper($pCoordinate))->setValueExplicit($pValue, $pDataType);
1118
        return ($returnCell) ? $cell : $this;
1119
    }
1120
1121
    /**
1122
     * Set a cell value by using numeric cell coordinates
1123
     *
1124
     * @param string $pColumn Numeric column coordinate of the cell
1125
     * @param string $pRow Numeric row coordinate of the cell
1126
     * @param mixed $pValue Value of the cell
1127
     * @param string $pDataType Explicit data type
1128
     * @param bool $returnCell Return the worksheet (false, default) or the cell (true)
1129
     * @return Worksheet|Cell    Depending on the last parameter being specified
1130
     */
1131
    public function setCellValueExplicitByColumnAndRow($pColumn = 0, $pRow = 1, $pValue = null, $pDataType = Cell\DataType::TYPE_STRING, $returnCell = false)
1132
    {
1133
        $cell = $this->getCellByColumnAndRow($pColumn, $pRow)->setValueExplicit($pValue, $pDataType);
1134
        return ($returnCell) ? $cell : $this;
1135
    }
1136
1137
    /**
1138
     * Get cell at a specific coordinate
1139
     *
1140
     * @param string $pCoordinate    Coordinate of the cell
1141
     * @param boolean $createIfNotExists  Flag indicating whether a new cell should be created if it doesn't
1142
     *                                       already exist, or a null should be returned instead
1143
     * @throws Exception
1144
     * @return null|Cell Cell that was found/created or null
1145
     */
1146
    public function getCell($pCoordinate = 'A1', $createIfNotExists = true)
1147
    {
1148
        // Check cell collection
1149
        if ($this->cellCollection->isDataSet(strtoupper($pCoordinate))) {
1150
            return $this->cellCollection->getCacheData($pCoordinate);
1151
        }
1152
1153
        // Worksheet reference?
1154 View Code Duplication
        if (strpos($pCoordinate, '!') !== 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...
1155
            $worksheetReference = Worksheet::extractSheetTitle($pCoordinate, true);
1156
            return $this->parent->getSheetByName($worksheetReference[0])->getCell(strtoupper($worksheetReference[1]), $createIfNotExists);
1157
        }
1158
1159
        // Named range?
1160
        if ((!preg_match('/^'.Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $pCoordinate, $matches)) &&
1161
            (preg_match('/^'.Calculation::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $pCoordinate, $matches))) {
1162
            $namedRange = NamedRange::resolveRange($pCoordinate, $this);
1163
            if ($namedRange !== null) {
1164
                $pCoordinate = $namedRange->getRange();
1165
                return $namedRange->getWorksheet()->getCell($pCoordinate, $createIfNotExists);
1166
            }
1167
        }
1168
1169
        // Uppercase coordinate
1170
        $pCoordinate = strtoupper($pCoordinate);
1171
1172 View Code Duplication
        if (strpos($pCoordinate, ':') !== false || strpos($pCoordinate, ',') !== 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...
1173
            throw new Exception('Cell coordinate can not be a range of cells.');
1174
        } elseif (strpos($pCoordinate, '$') !== false) {
1175
            throw new Exception('Cell coordinate must not be absolute.');
1176
        }
1177
1178
        // Create new cell object, if required
1179
        return $createIfNotExists ? $this->createNewCell($pCoordinate) : null;
1180
    }
1181
1182
    /**
1183
     * Get cell at a specific coordinate by using numeric cell coordinates
1184
     *
1185
     * @param  string $pColumn Numeric column coordinate of the cell
1186
     * @param string $pRow Numeric row coordinate of the cell
1187
     * @param boolean $createIfNotExists  Flag indicating whether a new cell should be created if it doesn't
1188
     *                                       already exist, or a null should be returned instead
1189
     * @return null|Cell Cell that was found/created or null
1190
     */
1191
    public function getCellByColumnAndRow($pColumn = 0, $pRow = 1, $createIfNotExists = true)
1192
    {
1193
        $columnLetter = Cell::stringFromColumnIndex($pColumn);
1194
        $coordinate = $columnLetter . $pRow;
1195
1196
        if ($this->cellCollection->isDataSet($coordinate)) {
1197
            return $this->cellCollection->getCacheData($coordinate);
1198
        }
1199
1200
        // Create new cell object, if required
1201
        return $createIfNotExists ? $this->createNewCell($coordinate) : null;
1202
    }
1203
1204
    /**
1205
     * Create a new cell at the specified coordinate
1206
     *
1207
     * @param string $pCoordinate    Coordinate of the cell
1208
     * @return Cell Cell that was created
1209
     */
1210
    private function createNewCell($pCoordinate)
1211
    {
1212
        $cell = $this->cellCollection->addCacheData(
1213
            $pCoordinate,
1214
            new Cell(null, Cell\DataType::TYPE_NULL, $this)
1215
        );
1216
        $this->cellCollectionIsSorted = false;
1217
1218
        // Coordinates
1219
        $aCoordinates = Cell::coordinateFromString($pCoordinate);
1220
        if (Cell::columnIndexFromString($this->cachedHighestColumn) < Cell::columnIndexFromString($aCoordinates[0])) {
1221
            $this->cachedHighestColumn = $aCoordinates[0];
1222
        }
1223
        $this->cachedHighestRow = max($this->cachedHighestRow, $aCoordinates[1]);
0 ignored issues
show
Documentation Bug introduced by
It seems like max($this->cachedHighestRow, $aCoordinates[1]) can also be of type string. However, the property $cachedHighestRow is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
1224
1225
        // Cell needs appropriate xfIndex from dimensions records
1226
        //    but don't create dimension records if they don't already exist
1227
        $rowDimension    = $this->getRowDimension($aCoordinates[1], false);
1228
        $columnDimension = $this->getColumnDimension($aCoordinates[0], false);
1229
1230
        if ($rowDimension !== null && $rowDimension->getXfIndex() > 0) {
1231
            // then there is a row dimension with explicit style, assign it to the cell
1232
            $cell->setXfIndex($rowDimension->getXfIndex());
1233
        } elseif ($columnDimension !== null && $columnDimension->getXfIndex() > 0) {
1234
            // then there is a column dimension, assign it to the cell
1235
            $cell->setXfIndex($columnDimension->getXfIndex());
1236
        }
1237
1238
        return $cell;
1239
    }
1240
1241
    /**
1242
     * Does the cell at a specific coordinate exist?
1243
     *
1244
     * @param string $pCoordinate  Coordinate of the cell
1245
     * @throws Exception
1246
     * @return boolean
1247
     */
1248
    public function cellExists($pCoordinate = 'A1')
1249
    {
1250
       // Worksheet reference?
1251 View Code Duplication
        if (strpos($pCoordinate, '!') !== 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...
1252
            $worksheetReference = Worksheet::extractSheetTitle($pCoordinate, true);
1253
            return $this->parent->getSheetByName($worksheetReference[0])->cellExists(strtoupper($worksheetReference[1]));
1254
        }
1255
1256
        // Named range?
1257
        if ((!preg_match('/^'.Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $pCoordinate, $matches)) &&
1258
            (preg_match('/^'.Calculation::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $pCoordinate, $matches))) {
1259
            $namedRange = NamedRange::resolveRange($pCoordinate, $this);
1260
            if ($namedRange !== null) {
1261
                $pCoordinate = $namedRange->getRange();
1262
                if ($this->getHashCode() != $namedRange->getWorksheet()->getHashCode()) {
1263
                    if (!$namedRange->getLocalOnly()) {
1264
                        return $namedRange->getWorksheet()->cellExists($pCoordinate);
1265
                    } else {
1266
                        throw new Exception('Named range ' . $namedRange->getName() . ' is not accessible from within sheet ' . $this->getTitle());
1267
                    }
1268
                }
1269
            } else {
1270
                return false;
1271
            }
1272
        }
1273
1274
        // Uppercase coordinate
1275
        $pCoordinate = strtoupper($pCoordinate);
1276
1277
        if (strpos($pCoordinate, ':') !== false || strpos($pCoordinate, ',') !== false) {
1278
            throw new Exception('Cell coordinate can not be a range of cells.');
1279
        } elseif (strpos($pCoordinate, '$') !== false) {
1280
            throw new Exception('Cell coordinate must not be absolute.');
1281
        } else {
1282
            // Coordinates
1283
            $aCoordinates = Cell::coordinateFromString($pCoordinate);
0 ignored issues
show
Unused Code introduced by
$aCoordinates 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...
1284
1285
            // Cell exists?
1286
            return $this->cellCollection->isDataSet($pCoordinate);
1287
        }
1288
    }
1289
1290
    /**
1291
     * Cell at a specific coordinate by using numeric cell coordinates exists?
1292
     *
1293
     * @param string $pColumn Numeric column coordinate of the cell
1294
     * @param string $pRow Numeric row coordinate of the cell
1295
     * @return boolean
1296
     */
1297
    public function cellExistsByColumnAndRow($pColumn = 0, $pRow = 1)
1298
    {
1299
        return $this->cellExists(Cell::stringFromColumnIndex($pColumn) . $pRow);
1300
    }
1301
1302
    /**
1303
     * Get row dimension at a specific row
1304
     *
1305
     * @param int $pRow Numeric index of the row
1306
     * @return Worksheet\RowDimension
1307
     */
1308
    public function getRowDimension($pRow = 1, $create = true)
1309
    {
1310
        // Found
1311
        $found = null;
0 ignored issues
show
Unused Code introduced by
$found 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...
1312
1313
        // Get row dimension
1314
        if (!isset($this->rowDimensions[$pRow])) {
1315
            if (!$create) {
1316
                return null;
1317
            }
1318
            $this->rowDimensions[$pRow] = new Worksheet\RowDimension($pRow);
1319
1320
            $this->cachedHighestRow = max($this->cachedHighestRow, $pRow);
1321
        }
1322
        return $this->rowDimensions[$pRow];
1323
    }
1324
1325
    /**
1326
     * Get column dimension at a specific column
1327
     *
1328
     * @param string $pColumn String index of the column
1329
     * @return Worksheet\ColumnDimension
1330
     */
1331
    public function getColumnDimension($pColumn = 'A', $create = true)
1332
    {
1333
        // Uppercase coordinate
1334
        $pColumn = strtoupper($pColumn);
1335
1336
        // Fetch dimensions
1337
        if (!isset($this->columnDimensions[$pColumn])) {
1338
            if (!$create) {
1339
                return null;
1340
            }
1341
            $this->columnDimensions[$pColumn] = new Worksheet\ColumnDimension($pColumn);
1342
1343
            if (Cell::columnIndexFromString($this->cachedHighestColumn) < Cell::columnIndexFromString($pColumn)) {
1344
                $this->cachedHighestColumn = $pColumn;
1345
            }
1346
        }
1347
        return $this->columnDimensions[$pColumn];
1348
    }
1349
1350
    /**
1351
     * Get column dimension at a specific column by using numeric cell coordinates
1352
     *
1353
     * @param string $pColumn Numeric column coordinate of the cell
1354
     * @return Worksheet\ColumnDimension
1355
     */
1356
    public function getColumnDimensionByColumn($pColumn = 0)
1357
    {
1358
        return $this->getColumnDimension(Cell::stringFromColumnIndex($pColumn));
1359
    }
1360
1361
    /**
1362
     * Get styles
1363
     *
1364
     * @return Style[]
1365
     */
1366
    public function getStyles()
1367
    {
1368
        return $this->styles;
1369
    }
1370
1371
    /**
1372
     * Get default style of workbook.
1373
     *
1374
     * @deprecated
1375
     * @return Style
1376
     * @throws Exception
1377
     */
1378
    public function getDefaultStyle()
1379
    {
1380
        return $this->parent->getDefaultStyle();
1381
    }
1382
1383
    /**
1384
     * Set default style - should only be used by \PhpSpreadsheet\IReader implementations!
1385
     *
1386
     * @deprecated
1387
     * @param Style $pValue
1388
     * @throws Exception
1389
     * @return Worksheet
1390
     */
1391
    public function setDefaultStyle(Style $pValue)
1392
    {
1393
        $this->parent->getDefaultStyle()->applyFromArray(array(
1394
            'font' => array(
1395
                'name' => $pValue->getFont()->getName(),
1396
                'size' => $pValue->getFont()->getSize(),
1397
            ),
1398
        ));
1399
        return $this;
1400
    }
1401
1402
    /**
1403
     * Get style for cell
1404
     *
1405
     * @param string $pCellCoordinate Cell coordinate (or range) to get style for
1406
     * @return Style
1407
     * @throws Exception
1408
     */
1409
    public function getStyle($pCellCoordinate = 'A1')
1410
    {
1411
        // set this sheet as active
1412
        $this->parent->setActiveSheetIndex($this->parent->getIndex($this));
1413
1414
        // set cell coordinate as active
1415
        $this->setSelectedCells(strtoupper($pCellCoordinate));
1416
1417
        return $this->parent->getCellXfSupervisor();
1418
    }
1419
1420
    /**
1421
     * Get conditional styles for a cell
1422
     *
1423
     * @param string $pCoordinate
1424
     * @return Style\Conditional[]
1425
     */
1426
    public function getConditionalStyles($pCoordinate = 'A1')
1427
    {
1428
        $pCoordinate = strtoupper($pCoordinate);
1429
        if (!isset($this->conditionalStylesCollection[$pCoordinate])) {
1430
            $this->conditionalStylesCollection[$pCoordinate] = array();
1431
        }
1432
        return $this->conditionalStylesCollection[$pCoordinate];
1433
    }
1434
1435
    /**
1436
     * Do conditional styles exist for this cell?
1437
     *
1438
     * @param string $pCoordinate
1439
     * @return boolean
1440
     */
1441
    public function conditionalStylesExists($pCoordinate = 'A1')
1442
    {
1443
        if (isset($this->conditionalStylesCollection[strtoupper($pCoordinate)])) {
1444
            return true;
1445
        }
1446
        return false;
1447
    }
1448
1449
    /**
1450
     * Removes conditional styles for a cell
1451
     *
1452
     * @param string $pCoordinate
1453
     * @return Worksheet
1454
     */
1455
    public function removeConditionalStyles($pCoordinate = 'A1')
1456
    {
1457
        unset($this->conditionalStylesCollection[strtoupper($pCoordinate)]);
1458
        return $this;
1459
    }
1460
1461
    /**
1462
     * Get collection of conditional styles
1463
     *
1464
     * @return array
1465
     */
1466
    public function getConditionalStylesCollection()
1467
    {
1468
        return $this->conditionalStylesCollection;
1469
    }
1470
1471
    /**
1472
     * Set conditional styles
1473
     *
1474
     * @param $pCoordinate string E.g. 'A1'
1475
     * @param $pValue Style\Conditional[]
1476
     * @return Worksheet
1477
     */
1478
    public function setConditionalStyles($pCoordinate, $pValue)
1479
    {
1480
        $this->conditionalStylesCollection[strtoupper($pCoordinate)] = $pValue;
1481
        return $this;
1482
    }
1483
1484
    /**
1485
     * Get style for cell by using numeric cell coordinates
1486
     *
1487
     * @param int $pColumn  Numeric column coordinate of the cell
1488
     * @param int $pRow Numeric row coordinate of the cell
1489
     * @param int pColumn2 Numeric column coordinate of the range cell
1490
     * @param int pRow2 Numeric row coordinate of the range cell
1491
     * @return Style
1492
     */
1493
    public function getStyleByColumnAndRow($pColumn = 0, $pRow = 1, $pColumn2 = null, $pRow2 = null)
1494
    {
1495
        if (!is_null($pColumn2) && !is_null($pRow2)) {
1496
            $cellRange = Cell::stringFromColumnIndex($pColumn) . $pRow . ':' . Cell::stringFromColumnIndex($pColumn2) . $pRow2;
1497
            return $this->getStyle($cellRange);
1498
        }
1499
1500
        return $this->getStyle(Cell::stringFromColumnIndex($pColumn) . $pRow);
1501
    }
1502
1503
    /**
1504
     * Set shared cell style to a range of cells
1505
     *
1506
     * Please note that this will overwrite existing cell styles for cells in range!
1507
     *
1508
     * @deprecated duplicateStyle
1509
     * @param Style $pSharedCellStyle Cell style to share
1510
     * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1")
1511
     * @throws Exception
1512
     * @return Worksheet
1513
     */
1514
    public function setSharedStyle(Style $pSharedCellStyle = null, $pRange = '')
1515
    {
1516
        $this->duplicateStyle($pSharedCellStyle, $pRange);
1517
        return $this;
1518
    }
1519
1520
    /**
1521
     * Duplicate cell style to a range of cells
1522
     *
1523
     * Please note that this will overwrite existing cell styles for cells in range!
1524
     *
1525
     * @param Style $pCellStyle Cell style to duplicate
1526
     * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1")
1527
     * @throws Exception
1528
     * @return Worksheet
1529
     */
1530
    public function duplicateStyle(Style $pCellStyle = null, $pRange = '')
1531
    {
1532
        // make sure we have a real style and not supervisor
1533
        $style = $pCellStyle->getIsSupervisor() ? $pCellStyle->getSharedComponent() : $pCellStyle;
0 ignored issues
show
Bug introduced by
It seems like $pCellStyle 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...
Unused Code introduced by
$style 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...
1534
1535
        // Add the style to the workbook if necessary
1536
        $workbook = $this->parent;
1537
        if ($existingStyle = $this->parent->getCellXfByHashCode($pCellStyle->getHashCode())) {
1538
            // there is already such cell Xf in our collection
1539
            $xfIndex = $existingStyle->getIndex();
1540
        } else {
1541
            // we don't have such a cell Xf, need to add
1542
            $workbook->addCellXf($pCellStyle);
0 ignored issues
show
Bug introduced by
It seems like $pCellStyle defined by parameter $pCellStyle on line 1530 can be null; however, PhpSpreadsheet\Spreadsheet::addCellXf() does not accept null, maybe add an additional type check?

It seems like you allow that null is being passed for a parameter, however the function which is called does not seem to accept null.

We recommend to add an additional type check (or disallow null for the parameter):

function notNullable(stdClass $x) { }

// Unsafe
function withoutCheck(stdClass $x = null) {
    notNullable($x);
}

// Safe - Alternative 1: Adding Additional Type-Check
function withCheck(stdClass $x = null) {
    if ($x instanceof stdClass) {
        notNullable($x);
    }
}

// Safe - Alternative 2: Changing Parameter
function withNonNullableParam(stdClass $x) {
    notNullable($x);
}
Loading history...
1543
            $xfIndex = $pCellStyle->getIndex();
1544
        }
1545
1546
        // Calculate range outer borders
1547
        list($rangeStart, $rangeEnd) = Cell::rangeBoundaries($pRange . ':' . $pRange);
1548
1549
        // Make sure we can loop upwards on rows and columns
1550 View Code Duplication
        if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) {
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...
1551
            $tmp = $rangeStart;
1552
            $rangeStart = $rangeEnd;
1553
            $rangeEnd = $tmp;
1554
        }
1555
1556
        // Loop through cells and apply styles
1557 View Code Duplication
        for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
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...
1558
            for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
1559
                $this->getCell(Cell::stringFromColumnIndex($col - 1) . $row)->setXfIndex($xfIndex);
1560
            }
1561
        }
1562
1563
        return $this;
1564
    }
1565
1566
    /**
1567
     * Duplicate conditional style to a range of cells
1568
     *
1569
     * Please note that this will overwrite existing cell styles for cells in range!
1570
     *
1571
     * @param    Style\Conditional[]    $pCellStyle    Cell style to duplicate
1572
     * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1")
1573
     * @throws Exception
1574
     * @return Worksheet
1575
     */
1576
    public function duplicateConditionalStyle(array $pCellStyle = null, $pRange = '')
1577
    {
1578
        foreach ($pCellStyle as $cellStyle) {
0 ignored issues
show
Bug introduced by
The expression $pCellStyle of type null|array<integer,objec...eet\Style\Conditional>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
1579
            if (!($cellStyle instanceof Style\Conditional)) {
1580
                throw new Exception('Style is not a conditional style');
1581
            }
1582
        }
1583
1584
        // Calculate range outer borders
1585
        list($rangeStart, $rangeEnd) = Cell::rangeBoundaries($pRange . ':' . $pRange);
1586
1587
        // Make sure we can loop upwards on rows and columns
1588 View Code Duplication
        if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) {
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...
1589
            $tmp = $rangeStart;
1590
            $rangeStart = $rangeEnd;
1591
            $rangeEnd = $tmp;
1592
        }
1593
1594
        // Loop through cells and apply styles
1595 View Code Duplication
        for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
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...
1596
            for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
1597
                $this->setConditionalStyles(Cell::stringFromColumnIndex($col - 1) . $row, $pCellStyle);
1598
            }
1599
        }
1600
1601
        return $this;
1602
    }
1603
1604
    /**
1605
     * Duplicate cell style array to a range of cells
1606
     *
1607
     * Please note that this will overwrite existing cell styles for cells in range,
1608
     * if they are in the styles array. For example, if you decide to set a range of
1609
     * cells to font bold, only include font bold in the styles array.
1610
     *
1611
     * @deprecated
1612
     * @param array $pStyles Array containing style information
1613
     * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1")
1614
     * @param boolean $pAdvanced Advanced mode for setting borders.
1615
     * @throws Exception
1616
     * @return Worksheet
1617
     */
1618
    public function duplicateStyleArray($pStyles = null, $pRange = '', $pAdvanced = true)
1619
    {
1620
        $this->getStyle($pRange)->applyFromArray($pStyles, $pAdvanced);
1621
        return $this;
1622
    }
1623
1624
    /**
1625
     * Set break on a cell
1626
     *
1627
     * @param string $pCell Cell coordinate (e.g. A1)
1628
     * @param int $pBreak Break type (type of Worksheet::BREAK_*)
1629
     * @throws Exception
1630
     * @return Worksheet
1631
     */
1632
    public function setBreak($pCell = 'A1', $pBreak = Worksheet::BREAK_NONE)
1633
    {
1634
        // Uppercase coordinate
1635
        $pCell = strtoupper($pCell);
1636
1637
        if ($pCell != '') {
1638
            if ($pBreak == Worksheet::BREAK_NONE) {
1639
                if (isset($this->breaks[$pCell])) {
1640
                    unset($this->breaks[$pCell]);
1641
                }
1642
            } else {
1643
                $this->breaks[$pCell] = $pBreak;
1644
            }
1645
        } else {
1646
            throw new Exception('No cell coordinate specified.');
1647
        }
1648
1649
        return $this;
1650
    }
1651
1652
    /**
1653
     * Set break on a cell by using numeric cell coordinates
1654
     *
1655
     * @param integer $pColumn Numeric column coordinate of the cell
1656
     * @param integer $pRow Numeric row coordinate of the cell
1657
     * @param  integer $pBreak Break type (type of \PhpSpreadsheet\Worksheet::BREAK_*)
1658
     * @return Worksheet
1659
     */
1660
    public function setBreakByColumnAndRow($pColumn = 0, $pRow = 1, $pBreak = Worksheet::BREAK_NONE)
1661
    {
1662
        return $this->setBreak(Cell::stringFromColumnIndex($pColumn) . $pRow, $pBreak);
1663
    }
1664
1665
    /**
1666
     * Get breaks
1667
     *
1668
     * @return array[]
1669
     */
1670
    public function getBreaks()
1671
    {
1672
        return $this->breaks;
1673
    }
1674
1675
    /**
1676
     * Set merge on a cell range
1677
     *
1678
     * @param string $pRange  Cell range (e.g. A1:E1)
1679
     * @throws Exception
1680
     * @return Worksheet
1681
     */
1682
    public function mergeCells($pRange = 'A1:A1')
1683
    {
1684
        // Uppercase coordinate
1685
        $pRange = strtoupper($pRange);
1686
1687
        if (strpos($pRange, ':') !== false) {
1688
            $this->mergeCells[$pRange] = $pRange;
1689
1690
            // make sure cells are created
1691
1692
            // get the cells in the range
1693
            $aReferences = Cell::extractAllCellReferencesInRange($pRange);
1694
1695
            // create upper left cell if it does not already exist
1696
            $upperLeft = $aReferences[0];
1697
            if (!$this->cellExists($upperLeft)) {
1698
                $this->getCell($upperLeft)->setValueExplicit(null, Cell\DataType::TYPE_NULL);
1699
            }
1700
1701
            // Blank out the rest of the cells in the range (if they exist)
1702
            $count = count($aReferences);
1703
            for ($i = 1; $i < $count; $i++) {
1704
                if ($this->cellExists($aReferences[$i])) {
1705
                    $this->getCell($aReferences[$i])->setValueExplicit(null, Cell\DataType::TYPE_NULL);
1706
                }
1707
            }
1708
        } else {
1709
            throw new Exception('Merge must be set on a range of cells.');
1710
        }
1711
1712
        return $this;
1713
    }
1714
1715
    /**
1716
     * Set merge on a cell range by using numeric cell coordinates
1717
     *
1718
     * @param int $pColumn1    Numeric column coordinate of the first cell
1719
     * @param int $pRow1        Numeric row coordinate of the first cell
1720
     * @param int $pColumn2    Numeric column coordinate of the last cell
1721
     * @param int $pRow2        Numeric row coordinate of the last cell
1722
     * @throws    Exception
1723
     * @return Worksheet
1724
     */
1725
    public function mergeCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1)
1726
    {
1727
        $cellRange = Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . Cell::stringFromColumnIndex($pColumn2) . $pRow2;
1728
        return $this->mergeCells($cellRange);
1729
    }
1730
1731
    /**
1732
     * Remove merge on a cell range
1733
     *
1734
     * @param    string            $pRange        Cell range (e.g. A1:E1)
1735
     * @throws    Exception
1736
     * @return Worksheet
1737
     */
1738
    public function unmergeCells($pRange = 'A1:A1')
1739
    {
1740
        // Uppercase coordinate
1741
        $pRange = strtoupper($pRange);
1742
1743
        if (strpos($pRange, ':') !== false) {
1744
            if (isset($this->mergeCells[$pRange])) {
1745
                unset($this->mergeCells[$pRange]);
1746
            } else {
1747
                throw new Exception('Cell range ' . $pRange . ' not known as merged.');
1748
            }
1749
        } else {
1750
            throw new Exception('Merge can only be removed from a range of cells.');
1751
        }
1752
1753
        return $this;
1754
    }
1755
1756
    /**
1757
     * Remove merge on a cell range by using numeric cell coordinates
1758
     *
1759
     * @param int $pColumn1    Numeric column coordinate of the first cell
1760
     * @param int $pRow1        Numeric row coordinate of the first cell
1761
     * @param int $pColumn2    Numeric column coordinate of the last cell
1762
     * @param int $pRow2        Numeric row coordinate of the last cell
1763
     * @throws    Exception
1764
     * @return Worksheet
1765
     */
1766
    public function unmergeCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1)
1767
    {
1768
        $cellRange = Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . Cell::stringFromColumnIndex($pColumn2) . $pRow2;
1769
        return $this->unmergeCells($cellRange);
1770
    }
1771
1772
    /**
1773
     * Get merge cells array.
1774
     *
1775
     * @return array[]
1776
     */
1777
    public function getMergeCells()
1778
    {
1779
        return $this->mergeCells;
1780
    }
1781
1782
    /**
1783
     * Set merge cells array for the entire sheet. Use instead mergeCells() to merge
1784
     * a single cell range.
1785
     *
1786
     * @param array
1787
     */
1788
    public function setMergeCells($pValue = array())
1789
    {
1790
        $this->mergeCells = $pValue;
1791
        return $this;
1792
    }
1793
1794
    /**
1795
     * Set protection on a cell range
1796
     *
1797
     * @param    string            $pRange                Cell (e.g. A1) or cell range (e.g. A1:E1)
1798
     * @param    string            $pPassword            Password to unlock the protection
1799
     * @param    boolean        $pAlreadyHashed    If the password has already been hashed, set this to true
1800
     * @throws    Exception
1801
     * @return Worksheet
1802
     */
1803
    public function protectCells($pRange = 'A1', $pPassword = '', $pAlreadyHashed = false)
1804
    {
1805
        // Uppercase coordinate
1806
        $pRange = strtoupper($pRange);
1807
1808
        if (!$pAlreadyHashed) {
1809
            $pPassword = Shared\PasswordHasher::hashPassword($pPassword);
1810
        }
1811
        $this->protectedCells[$pRange] = $pPassword;
1812
1813
        return $this;
1814
    }
1815
1816
    /**
1817
     * Set protection on a cell range by using numeric cell coordinates
1818
     *
1819
     * @param int  $pColumn1            Numeric column coordinate of the first cell
1820
     * @param int  $pRow1                Numeric row coordinate of the first cell
1821
     * @param int  $pColumn2            Numeric column coordinate of the last cell
1822
     * @param int  $pRow2                Numeric row coordinate of the last cell
1823
     * @param string $pPassword            Password to unlock the protection
1824
     * @param    boolean $pAlreadyHashed    If the password has already been hashed, set this to true
1825
     * @throws    Exception
1826
     * @return Worksheet
1827
     */
1828
    public function protectCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1, $pPassword = '', $pAlreadyHashed = false)
1829
    {
1830
        $cellRange = Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . Cell::stringFromColumnIndex($pColumn2) . $pRow2;
1831
        return $this->protectCells($cellRange, $pPassword, $pAlreadyHashed);
1832
    }
1833
1834
    /**
1835
     * Remove protection on a cell range
1836
     *
1837
     * @param    string            $pRange        Cell (e.g. A1) or cell range (e.g. A1:E1)
1838
     * @throws    Exception
1839
     * @return Worksheet
1840
     */
1841
    public function unprotectCells($pRange = 'A1')
1842
    {
1843
        // Uppercase coordinate
1844
        $pRange = strtoupper($pRange);
1845
1846
        if (isset($this->protectedCells[$pRange])) {
1847
            unset($this->protectedCells[$pRange]);
1848
        } else {
1849
            throw new Exception('Cell range ' . $pRange . ' not known as protected.');
1850
        }
1851
        return $this;
1852
    }
1853
1854
    /**
1855
     * Remove protection on a cell range by using numeric cell coordinates
1856
     *
1857
     * @param int  $pColumn1            Numeric column coordinate of the first cell
1858
     * @param int  $pRow1                Numeric row coordinate of the first cell
1859
     * @param int  $pColumn2            Numeric column coordinate of the last cell
1860
     * @param int $pRow2                Numeric row coordinate of the last cell
1861
     * @param string $pPassword            Password to unlock the protection
1862
     * @param    boolean $pAlreadyHashed    If the password has already been hashed, set this to true
1863
     * @throws    Exception
1864
     * @return Worksheet
1865
     */
1866
    public function unprotectCellsByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1, $pPassword = '', $pAlreadyHashed = false)
1867
    {
1868
        $cellRange = Cell::stringFromColumnIndex($pColumn1) . $pRow1 . ':' . Cell::stringFromColumnIndex($pColumn2) . $pRow2;
1869
        return $this->unprotectCells($cellRange, $pPassword, $pAlreadyHashed);
0 ignored issues
show
Unused Code introduced by
The call to Worksheet::unprotectCells() has too many arguments starting with $pPassword.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
1870
    }
1871
1872
    /**
1873
     * Get protected cells
1874
     *
1875
     * @return array[]
1876
     */
1877
    public function getProtectedCells()
1878
    {
1879
        return $this->protectedCells;
1880
    }
1881
1882
    /**
1883
     *    Get Autofilter
1884
     *
1885
     *    @return Worksheet\AutoFilter
1886
     */
1887
    public function getAutoFilter()
1888
    {
1889
        return $this->autoFilter;
1890
    }
1891
1892
    /**
1893
     *    Set AutoFilter
1894
     *
1895
     *    @param    Worksheet\AutoFilter|string   $pValue
1896
     *            A simple string containing a Cell range like 'A1:E10' is permitted for backward compatibility
1897
     *    @throws Exception
1898
     *    @return Worksheet
1899
     */
1900
    public function setAutoFilter($pValue)
1901
    {
1902
        $pRange = strtoupper($pValue);
0 ignored issues
show
Unused Code introduced by
$pRange 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...
1903
        if (is_string($pValue)) {
1904
            $this->autoFilter->setRange($pValue);
1905
        } elseif (is_object($pValue) && ($pValue instanceof Worksheet\AutoFilter)) {
1906
            $this->autoFilter = $pValue;
1907
        }
1908
        return $this;
1909
    }
1910
1911
    /**
1912
     *    Set Autofilter Range by using numeric cell coordinates
1913
     *
1914
     *    @param  integer  $pColumn1    Numeric column coordinate of the first cell
1915
     *    @param  integer  $pRow1       Numeric row coordinate of the first cell
1916
     *    @param  integer  $pColumn2    Numeric column coordinate of the second cell
1917
     *    @param  integer  $pRow2       Numeric row coordinate of the second cell
1918
     *    @throws    Exception
1919
     *    @return Worksheet
1920
     */
1921
    public function setAutoFilterByColumnAndRow($pColumn1 = 0, $pRow1 = 1, $pColumn2 = 0, $pRow2 = 1)
1922
    {
1923
        return $this->setAutoFilter(
1924
            Cell::stringFromColumnIndex($pColumn1) . $pRow1
1925
            . ':' .
1926
            Cell::stringFromColumnIndex($pColumn2) . $pRow2
1927
        );
1928
    }
1929
1930
    /**
1931
     * Remove autofilter
1932
     *
1933
     * @return Worksheet
1934
     */
1935
    public function removeAutoFilter()
1936
    {
1937
        $this->autoFilter->setRange(null);
1938
        return $this;
1939
    }
1940
1941
    /**
1942
     * Get Freeze Pane
1943
     *
1944
     * @return string
1945
     */
1946
    public function getFreezePane()
1947
    {
1948
        return $this->freezePane;
1949
    }
1950
1951
    /**
1952
     * Freeze Pane
1953
     *
1954
     * @param    string        $pCell        Cell (i.e. A2)
1955
     *                                    Examples:
1956
     *                                        A2 will freeze the rows above cell A2 (i.e row 1)
1957
     *                                        B1 will freeze the columns to the left of cell B1 (i.e column A)
1958
     *                                        B2 will freeze the rows above and to the left of cell A2
1959
     *                                            (i.e row 1 and column A)
1960
     * @throws    Exception
1961
     * @return Worksheet
1962
     */
1963
    public function freezePane($pCell = '')
1964
    {
1965
        // Uppercase coordinate
1966
        $pCell = strtoupper($pCell);
1967
        if (strpos($pCell, ':') === false && strpos($pCell, ',') === false) {
1968
            $this->freezePane = $pCell;
1969
        } else {
1970
            throw new Exception('Freeze pane can not be set on a range of cells.');
1971
        }
1972
        return $this;
1973
    }
1974
1975
    /**
1976
     * Freeze Pane by using numeric cell coordinates
1977
     *
1978
     * @param int $pColumn    Numeric column coordinate of the cell
1979
     * @param int $pRow        Numeric row coordinate of the cell
1980
     * @throws    Exception
1981
     * @return Worksheet
1982
     */
1983
    public function freezePaneByColumnAndRow($pColumn = 0, $pRow = 1)
1984
    {
1985
        return $this->freezePane(Cell::stringFromColumnIndex($pColumn) . $pRow);
1986
    }
1987
1988
    /**
1989
     * Unfreeze Pane
1990
     *
1991
     * @return Worksheet
1992
     */
1993
    public function unfreezePane()
1994
    {
1995
        return $this->freezePane('');
1996
    }
1997
1998
    /**
1999
     * Insert a new row, updating all possible related data
2000
     *
2001
     * @param int $pBefore    Insert before this one
2002
     * @param int $pNumRows    Number of rows to insert
2003
     * @throws    Exception
2004
     * @return Worksheet
2005
     */
2006 View Code Duplication
    public function insertNewRowBefore($pBefore = 1, $pNumRows = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2007
    {
2008
        if ($pBefore >= 1) {
2009
            $objReferenceHelper = ReferenceHelper::getInstance();
2010
            $objReferenceHelper->insertNewBefore('A' . $pBefore, 0, $pNumRows, $this);
2011
        } else {
2012
            throw new Exception("Rows can only be inserted before at least row 1.");
2013
        }
2014
        return $this;
2015
    }
2016
2017
    /**
2018
     * Insert a new column, updating all possible related data
2019
     *
2020
     * @param int $pBefore    Insert before this one
2021
     * @param int $pNumCols    Number of columns to insert
2022
     * @throws    Exception
2023
     * @return Worksheet
2024
     */
2025 View Code Duplication
    public function insertNewColumnBefore($pBefore = 'A', $pNumCols = 1)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2026
    {
2027
        if (!is_numeric($pBefore)) {
2028
            $objReferenceHelper = ReferenceHelper::getInstance();
2029
            $objReferenceHelper->insertNewBefore($pBefore . '1', $pNumCols, 0, $this);
2030
        } else {
2031
            throw new Exception("Column references should not be numeric.");
2032
        }
2033
        return $this;
2034
    }
2035
2036
    /**
2037
     * Insert a new column, updating all possible related data
2038
     *
2039
     * @param int $pBefore    Insert before this one (numeric column coordinate of the cell)
2040
     * @param int $pNumCols    Number of columns to insert
2041
     * @throws    Exception
2042
     * @return Worksheet
2043
     */
2044
    public function insertNewColumnBeforeByIndex($pBefore = 0, $pNumCols = 1)
2045
    {
2046
        if ($pBefore >= 0) {
2047
            return $this->insertNewColumnBefore(Cell::stringFromColumnIndex($pBefore), $pNumCols);
2048
        } else {
2049
            throw new Exception("Columns can only be inserted before at least column A (0).");
2050
        }
2051
    }
2052
2053
    /**
2054
     * Delete a row, updating all possible related data
2055
     *
2056
     * @param int $pRow        Remove starting with this one
2057
     * @param int $pNumRows    Number of rows to remove
2058
     * @throws    Exception
2059
     * @return Worksheet
2060
     */
2061
    public function removeRow($pRow = 1, $pNumRows = 1)
2062
    {
2063
        if ($pRow >= 1) {
2064
            $highestRow = $this->getHighestDataRow();
2065
            $objReferenceHelper = ReferenceHelper::getInstance();
2066
            $objReferenceHelper->insertNewBefore('A' . ($pRow + $pNumRows), 0, -$pNumRows, $this);
2067
            for ($r = 0; $r < $pNumRows; ++$r) {
2068
                $this->getCellCacheController()->removeRow($highestRow);
2069
                --$highestRow;
2070
            }
2071
        } else {
2072
            throw new Exception("Rows to be deleted should at least start from row 1.");
2073
        }
2074
        return $this;
2075
    }
2076
2077
    /**
2078
     * Remove a column, updating all possible related data
2079
     *
2080
     * @param string    $pColumn     Remove starting with this one
2081
     * @param int       $pNumCols    Number of columns to remove
2082
     * @throws    Exception
2083
     * @return Worksheet
2084
     */
2085
    public function removeColumn($pColumn = 'A', $pNumCols = 1)
2086
    {
2087
        if (!is_numeric($pColumn)) {
2088
            $highestColumn = $this->getHighestDataColumn();
2089
            $pColumn = Cell::stringFromColumnIndex(Cell::columnIndexFromString($pColumn) - 1 + $pNumCols);
2090
            $objReferenceHelper = ReferenceHelper::getInstance();
2091
            $objReferenceHelper->insertNewBefore($pColumn . '1', -$pNumCols, 0, $this);
2092
            for ($c = 0; $c < $pNumCols; ++$c) {
2093
                $this->getCellCacheController()->removeColumn($highestColumn);
2094
                $highestColumn = Cell::stringFromColumnIndex(Cell::columnIndexFromString($highestColumn) - 2);
2095
            }
2096
        } else {
2097
            throw new Exception("Column references should not be numeric.");
2098
        }
2099
        return $this;
2100
    }
2101
2102
    /**
2103
     * Remove a column, updating all possible related data
2104
     *
2105
     * @param int $pColumn    Remove starting with this one (numeric column coordinate of the cell)
2106
     * @param int $pNumCols    Number of columns to remove
2107
     * @throws    Exception
2108
     * @return Worksheet
2109
     */
2110
    public function removeColumnByIndex($pColumn = 0, $pNumCols = 1)
2111
    {
2112
        if ($pColumn >= 0) {
2113
            return $this->removeColumn(Cell::stringFromColumnIndex($pColumn), $pNumCols);
2114
        } else {
2115
            throw new Exception("Columns to be deleted should at least start from column 0");
2116
        }
2117
    }
2118
2119
    /**
2120
     * Show gridlines?
2121
     *
2122
     * @return boolean
2123
     */
2124
    public function getShowGridlines()
2125
    {
2126
        return $this->showGridlines;
2127
    }
2128
2129
    /**
2130
     * Set show gridlines
2131
     *
2132
     * @param boolean $pValue    Show gridlines (true/false)
2133
     * @return Worksheet
2134
     */
2135
    public function setShowGridlines($pValue = false)
2136
    {
2137
        $this->showGridlines = $pValue;
2138
        return $this;
2139
    }
2140
2141
    /**
2142
    * Print gridlines?
2143
    *
2144
    * @return boolean
2145
    */
2146
    public function getPrintGridlines()
2147
    {
2148
        return $this->printGridlines;
2149
    }
2150
2151
    /**
2152
    * Set print gridlines
2153
    *
2154
    * @param boolean $pValue Print gridlines (true/false)
2155
    * @return Worksheet
2156
    */
2157
    public function setPrintGridlines($pValue = false)
2158
    {
2159
        $this->printGridlines = $pValue;
2160
        return $this;
2161
    }
2162
2163
    /**
2164
    * Show row and column headers?
2165
    *
2166
    * @return boolean
2167
    */
2168
    public function getShowRowColHeaders()
2169
    {
2170
        return $this->showRowColHeaders;
2171
    }
2172
2173
    /**
2174
    * Set show row and column headers
2175
    *
2176
    * @param boolean $pValue Show row and column headers (true/false)
2177
    * @return Worksheet
2178
    */
2179
    public function setShowRowColHeaders($pValue = false)
2180
    {
2181
        $this->showRowColHeaders = $pValue;
2182
        return $this;
2183
    }
2184
2185
    /**
2186
     * Show summary below? (Row/Column outlining)
2187
     *
2188
     * @return boolean
2189
     */
2190
    public function getShowSummaryBelow()
2191
    {
2192
        return $this->showSummaryBelow;
2193
    }
2194
2195
    /**
2196
     * Set show summary below
2197
     *
2198
     * @param boolean $pValue    Show summary below (true/false)
2199
     * @return Worksheet
2200
     */
2201
    public function setShowSummaryBelow($pValue = true)
2202
    {
2203
        $this->showSummaryBelow = $pValue;
2204
        return $this;
2205
    }
2206
2207
    /**
2208
     * Show summary right? (Row/Column outlining)
2209
     *
2210
     * @return boolean
2211
     */
2212
    public function getShowSummaryRight()
2213
    {
2214
        return $this->showSummaryRight;
2215
    }
2216
2217
    /**
2218
     * Set show summary right
2219
     *
2220
     * @param boolean $pValue    Show summary right (true/false)
2221
     * @return Worksheet
2222
     */
2223
    public function setShowSummaryRight($pValue = true)
2224
    {
2225
        $this->showSummaryRight = $pValue;
2226
        return $this;
2227
    }
2228
2229
    /**
2230
     * Get comments
2231
     *
2232
     * @return Comment[]
2233
     */
2234
    public function getComments()
2235
    {
2236
        return $this->comments;
2237
    }
2238
2239
    /**
2240
     * Set comments array for the entire sheet.
2241
     *
2242
     * @param array of Comment
2243
     * @return Worksheet
2244
     */
2245
    public function setComments($pValue = array())
2246
    {
2247
        $this->comments = $pValue;
2248
2249
        return $this;
2250
    }
2251
2252
    /**
2253
     * Get comment for cell
2254
     *
2255
     * @param string $pCellCoordinate    Cell coordinate to get comment for
2256
     * @return Comment
2257
     * @throws Exception
2258
     */
2259
    public function getComment($pCellCoordinate = 'A1')
2260
    {
2261
        // Uppercase coordinate
2262
        $pCellCoordinate = strtoupper($pCellCoordinate);
2263
2264
        if (strpos($pCellCoordinate, ':') !== false || strpos($pCellCoordinate, ',') !== false) {
2265
            throw new Exception('Cell coordinate string can not be a range of cells.');
2266
        } elseif (strpos($pCellCoordinate, '$') !== false) {
2267
            throw new Exception('Cell coordinate string must not be absolute.');
2268
        } elseif ($pCellCoordinate == '') {
2269
            throw new Exception('Cell coordinate can not be zero-length string.');
2270
        } else {
2271
            // Check if we already have a comment for this cell.
2272
            // If not, create a new comment.
2273
            if (isset($this->comments[$pCellCoordinate])) {
2274
                return $this->comments[$pCellCoordinate];
2275
            } else {
2276
                $newComment = new Comment();
2277
                $this->comments[$pCellCoordinate] = $newComment;
2278
                return $newComment;
2279
            }
2280
        }
2281
    }
2282
2283
    /**
2284
     * Get comment for cell by using numeric cell coordinates
2285
     *
2286
     * @param int $pColumn    Numeric column coordinate of the cell
2287
     * @param int $pRow        Numeric row coordinate of the cell
2288
     * @return Comment
2289
     */
2290
    public function getCommentByColumnAndRow($pColumn = 0, $pRow = 1)
2291
    {
2292
        return $this->getComment(Cell::stringFromColumnIndex($pColumn) . $pRow);
2293
    }
2294
2295
    /**
2296
     * Get selected cell
2297
     *
2298
     * @deprecated
2299
     * @return string
2300
     */
2301
    public function getSelectedCell()
2302
    {
2303
        return $this->getSelectedCells();
2304
    }
2305
2306
    /**
2307
     * Get active cell
2308
     *
2309
     * @return string Example: 'A1'
2310
     */
2311
    public function getActiveCell()
2312
    {
2313
        return $this->activeCell;
2314
    }
2315
2316
    /**
2317
     * Get selected cells
2318
     *
2319
     * @return string
2320
     */
2321
    public function getSelectedCells()
2322
    {
2323
        return $this->selectedCells;
2324
    }
2325
2326
    /**
2327
     * Selected cell
2328
     *
2329
     * @param    string        $pCoordinate    Cell (i.e. A1)
2330
     * @return Worksheet
2331
     */
2332
    public function setSelectedCell($pCoordinate = 'A1')
2333
    {
2334
        return $this->setSelectedCells($pCoordinate);
2335
    }
2336
2337
    /**
2338
     * Select a range of cells.
2339
     *
2340
     * @param    string        $pCoordinate    Cell range, examples: 'A1', 'B2:G5', 'A:C', '3:6'
2341
     * @throws    Exception
2342
     * @return Worksheet
2343
     */
2344
    public function setSelectedCells($pCoordinate = 'A1')
2345
    {
2346
        // Uppercase coordinate
2347
        $pCoordinate = strtoupper($pCoordinate);
2348
2349
        // Convert 'A' to 'A:A'
2350
        $pCoordinate = preg_replace('/^([A-Z]+)$/', '${1}:${1}', $pCoordinate);
2351
2352
        // Convert '1' to '1:1'
2353
        $pCoordinate = preg_replace('/^([0-9]+)$/', '${1}:${1}', $pCoordinate);
2354
2355
        // Convert 'A:C' to 'A1:C1048576'
2356
        $pCoordinate = preg_replace('/^([A-Z]+):([A-Z]+)$/', '${1}1:${2}1048576', $pCoordinate);
2357
2358
        // Convert '1:3' to 'A1:XFD3'
2359
        $pCoordinate = preg_replace('/^([0-9]+):([0-9]+)$/', 'A${1}:XFD${2}', $pCoordinate);
2360
2361
        if (strpos($pCoordinate, ':') !== false || strpos($pCoordinate, ',') !== false) {
2362
            list($first, ) = Cell::splitRange($pCoordinate);
2363
            $this->activeCell = $first[0];
2364
        } else {
2365
            $this->activeCell = $pCoordinate;
2366
        }
2367
        $this->selectedCells = $pCoordinate;
2368
        return $this;
2369
    }
2370
2371
    /**
2372
     * Selected cell by using numeric cell coordinates
2373
     *
2374
     * @param int $pColumn Numeric column coordinate of the cell
2375
     * @param int $pRow Numeric row coordinate of the cell
2376
     * @throws Exception
2377
     * @return Worksheet
2378
     */
2379
    public function setSelectedCellByColumnAndRow($pColumn = 0, $pRow = 1)
2380
    {
2381
        return $this->setSelectedCells(Cell::stringFromColumnIndex($pColumn) . $pRow);
2382
    }
2383
2384
    /**
2385
     * Get right-to-left
2386
     *
2387
     * @return boolean
2388
     */
2389
    public function getRightToLeft()
2390
    {
2391
        return $this->rightToLeft;
2392
    }
2393
2394
    /**
2395
     * Set right-to-left
2396
     *
2397
     * @param boolean $value    Right-to-left true/false
2398
     * @return Worksheet
2399
     */
2400
    public function setRightToLeft($value = false)
2401
    {
2402
        $this->rightToLeft = $value;
2403
        return $this;
2404
    }
2405
2406
    /**
2407
     * Fill worksheet from values in array
2408
     *
2409
     * @param array $source Source array
2410
     * @param mixed $nullValue Value in source array that stands for blank cell
2411
     * @param string $startCell Insert array starting from this cell address as the top left coordinate
2412
     * @param boolean $strictNullComparison Apply strict comparison when testing for null values in the array
2413
     * @throws Exception
2414
     * @return Worksheet
2415
     */
2416
    public function fromArray($source = null, $nullValue = null, $startCell = 'A1', $strictNullComparison = false)
2417
    {
2418
        if (is_array($source)) {
2419
            //    Convert a 1-D array to 2-D (for ease of looping)
2420
            if (!is_array(end($source))) {
2421
                $source = array($source);
2422
            }
2423
2424
            // start coordinate
2425
            list ($startColumn, $startRow) = Cell::coordinateFromString($startCell);
2426
2427
            // Loop through $source
2428
            foreach ($source as $rowData) {
2429
                $currentColumn = $startColumn;
2430
                foreach ($rowData as $cellValue) {
2431
                    if ($strictNullComparison) {
2432
                        if ($cellValue !== $nullValue) {
2433
                            // Set cell value
2434
                            $this->getCell($currentColumn . $startRow)->setValue($cellValue);
2435
                        }
2436
                    } else {
2437
                        if ($cellValue != $nullValue) {
2438
                            // Set cell value
2439
                            $this->getCell($currentColumn . $startRow)->setValue($cellValue);
2440
                        }
2441
                    }
2442
                    ++$currentColumn;
2443
                }
2444
                ++$startRow;
2445
            }
2446
        } else {
2447
            throw new Exception("Parameter \$source should be an array.");
2448
        }
2449
        return $this;
2450
    }
2451
2452
    /**
2453
     * Create array from a range of cells
2454
     *
2455
     * @param string $pRange Range of cells (i.e. "A1:B10"), or just one cell (i.e. "A1")
2456
     * @param mixed $nullValue Value returned in the array entry if a cell doesn't exist
2457
     * @param boolean $calculateFormulas Should formulas be calculated?
2458
     * @param boolean $formatData Should formatting be applied to cell values?
2459
     * @param boolean $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero
2460
     *                               True - Return rows and columns indexed by their actual row and column IDs
2461
     * @return array
2462
     */
2463
    public function rangeToArray($pRange = 'A1', $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false)
2464
    {
2465
        // Returnvalue
2466
        $returnValue = array();
2467
        //    Identify the range that we need to extract from the worksheet
2468
        list($rangeStart, $rangeEnd) = Cell::rangeBoundaries($pRange);
2469
        $minCol = Cell::stringFromColumnIndex($rangeStart[0] -1);
2470
        $minRow = $rangeStart[1];
2471
        $maxCol = Cell::stringFromColumnIndex($rangeEnd[0] -1);
2472
        $maxRow = $rangeEnd[1];
2473
2474
        $maxCol++;
2475
        // Loop through rows
2476
        $r = -1;
2477
        for ($row = $minRow; $row <= $maxRow; ++$row) {
2478
            $rRef = ($returnCellRef) ? $row : ++$r;
2479
            $c = -1;
2480
            // Loop through columns in the current row
2481
            for ($col = $minCol; $col != $maxCol; ++$col) {
2482
                $cRef = ($returnCellRef) ? $col : ++$c;
2483
                //    Using getCell() will create a new cell if it doesn't already exist. We don't want that to happen
2484
                //        so we test and retrieve directly against cellCollection
2485
                if ($this->cellCollection->isDataSet($col.$row)) {
2486
                    // Cell exists
2487
                    $cell = $this->cellCollection->getCacheData($col.$row);
2488
                    if ($cell->getValue() !== null) {
2489
                        if ($cell->getValue() instanceof RichText) {
2490
                            $returnValue[$rRef][$cRef] = $cell->getValue()->getPlainText();
2491
                        } else {
2492
                            if ($calculateFormulas) {
2493
                                $returnValue[$rRef][$cRef] = $cell->getCalculatedValue();
2494
                            } else {
2495
                                $returnValue[$rRef][$cRef] = $cell->getValue();
2496
                            }
2497
                        }
2498
2499
                        if ($formatData) {
2500
                            $style = $this->parent->getCellXfByIndex($cell->getXfIndex());
2501
                            $returnValue[$rRef][$cRef] = Style\NumberFormat::toFormattedString(
2502
                                $returnValue[$rRef][$cRef],
2503
                                ($style && $style->getNumberFormat()) ? $style->getNumberFormat()->getFormatCode() : Style\NumberFormat::FORMAT_GENERAL
2504
                            );
2505
                        }
2506
                    } else {
2507
                        // Cell holds a NULL
2508
                        $returnValue[$rRef][$cRef] = $nullValue;
2509
                    }
2510
                } else {
2511
                    // Cell doesn't exist
2512
                    $returnValue[$rRef][$cRef] = $nullValue;
2513
                }
2514
            }
2515
        }
2516
2517
        // Return
2518
        return $returnValue;
2519
    }
2520
2521
2522
    /**
2523
     * Create array from a range of cells
2524
     *
2525
     * @param  string $pNamedRange Name of the Named Range
2526
     * @param  mixed  $nullValue Value returned in the array entry if a cell doesn't exist
2527
     * @param  boolean $calculateFormulas  Should formulas be calculated?
2528
     * @param  boolean $formatData  Should formatting be applied to cell values?
2529
     * @param  boolean $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero
2530
     *                                True - Return rows and columns indexed by their actual row and column IDs
2531
     * @return array
2532
     * @throws Exception
2533
     */
2534
    public function namedRangeToArray($pNamedRange = '', $nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false)
2535
    {
2536
        $namedRange = NamedRange::resolveRange($pNamedRange, $this);
2537
        if ($namedRange !== null) {
2538
            $pWorkSheet = $namedRange->getWorksheet();
2539
            $pCellRange = $namedRange->getRange();
2540
2541
            return $pWorkSheet->rangeToArray($pCellRange, $nullValue, $calculateFormulas, $formatData, $returnCellRef);
2542
        }
2543
2544
        throw new Exception('Named Range '.$pNamedRange.' does not exist.');
2545
    }
2546
2547
2548
    /**
2549
     * Create array from worksheet
2550
     *
2551
     * @param mixed $nullValue Value returned in the array entry if a cell doesn't exist
2552
     * @param boolean $calculateFormulas Should formulas be calculated?
2553
     * @param boolean $formatData  Should formatting be applied to cell values?
2554
     * @param boolean $returnCellRef False - Return a simple array of rows and columns indexed by number counting from zero
2555
     *                               True - Return rows and columns indexed by their actual row and column IDs
2556
     * @return array
2557
     */
2558
    public function toArray($nullValue = null, $calculateFormulas = true, $formatData = true, $returnCellRef = false)
2559
    {
2560
        // Garbage collect...
2561
        $this->garbageCollect();
2562
2563
        //    Identify the range that we need to extract from the worksheet
2564
        $maxCol = $this->getHighestColumn();
2565
        $maxRow = $this->getHighestRow();
2566
        // Return
2567
        return $this->rangeToArray('A1:'.$maxCol.$maxRow, $nullValue, $calculateFormulas, $formatData, $returnCellRef);
2568
    }
2569
2570
    /**
2571
     * Get row iterator
2572
     *
2573
     * @param   integer   $startRow   The row number at which to start iterating
2574
     * @param   integer   $endRow     The row number at which to stop iterating
2575
     *
2576
     * @return Worksheet\RowIterator
2577
     */
2578
    public function getRowIterator($startRow = 1, $endRow = null)
2579
    {
2580
        return new Worksheet\RowIterator($this, $startRow, $endRow);
2581
    }
2582
2583
    /**
2584
     * Get column iterator
2585
     *
2586
     * @param   string   $startColumn The column address at which to start iterating
2587
     * @param   string   $endColumn   The column address at which to stop iterating
2588
     *
2589
     * @return Worksheet\ColumnIterator
2590
     */
2591
    public function getColumnIterator($startColumn = 'A', $endColumn = null)
2592
    {
2593
        return new Worksheet\ColumnIterator($this, $startColumn, $endColumn);
2594
    }
2595
2596
    /**
2597
     * Run PhpSpreadsheet garabage collector.
2598
     *
2599
     * @return Worksheet
2600
     */
2601
    public function garbageCollect()
2602
    {
2603
        // Flush cache
2604
        $this->cellCollection->getCacheData('A1');
2605
        // Build a reference table from images
0 ignored issues
show
Unused Code Comprehensibility introduced by
49% 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...
2606
//        $imageCoordinates = array();
2607
//        $iterator = $this->getDrawingCollection()->getIterator();
2608
//        while ($iterator->valid()) {
2609
//            $imageCoordinates[$iterator->current()->getCoordinates()] = true;
2610
//
2611
//            $iterator->next();
2612
//        }
2613
//
2614
        // Lookup highest column and highest row if cells are cleaned
2615
        $colRow = $this->cellCollection->getHighestRowAndColumn();
2616
        $highestRow = $colRow['row'];
2617
        $highestColumn = Cell::columnIndexFromString($colRow['column']);
2618
2619
        // Loop through column dimensions
2620
        foreach ($this->columnDimensions as $dimension) {
2621
            $highestColumn = max($highestColumn, Cell::columnIndexFromString($dimension->getColumnIndex()));
2622
        }
2623
2624
        // Loop through row dimensions
2625
        foreach ($this->rowDimensions as $dimension) {
2626
            $highestRow = max($highestRow, $dimension->getRowIndex());
2627
        }
2628
2629
        // Cache values
2630
        if ($highestColumn < 0) {
2631
            $this->cachedHighestColumn = 'A';
2632
        } else {
2633
            $this->cachedHighestColumn = Cell::stringFromColumnIndex(--$highestColumn);
2634
        }
2635
        $this->cachedHighestRow = $highestRow;
2636
2637
        // Return
2638
        return $this;
2639
    }
2640
2641
    /**
2642
     * Get hash code
2643
     *
2644
     * @return string    Hash code
2645
     */
2646
    public function getHashCode()
2647
    {
2648
        if ($this->dirty) {
2649
            $this->hash = md5($this->title . $this->autoFilter . ($this->protection->isProtectionEnabled() ? 't' : 'f') . __CLASS__);
2650
            $this->dirty = false;
2651
        }
2652
        return $this->hash;
2653
    }
2654
2655
    /**
2656
     * Extract worksheet title from range.
2657
     *
2658
     * Example: extractSheetTitle("testSheet!A1") ==> 'A1'
2659
     * Example: extractSheetTitle("'testSheet 1'!A1", true) ==> array('testSheet 1', 'A1');
2660
     *
2661
     * @param string $pRange    Range to extract title from
2662
     * @param bool $returnRange    Return range? (see example)
2663
     * @return mixed
2664
     */
2665
    public static function extractSheetTitle($pRange, $returnRange = false)
2666
    {
2667
        // Sheet title included?
2668
        if (($sep = strpos($pRange, '!')) === false) {
2669
            return '';
2670
        }
2671
2672
        if ($returnRange) {
2673
            return array(trim(substr($pRange, 0, $sep), "'"), substr($pRange, $sep + 1));
2674
        }
2675
2676
        return substr($pRange, $sep + 1);
2677
    }
2678
2679
    /**
2680
     * Get hyperlink
2681
     *
2682
     * @param string $pCellCoordinate    Cell coordinate to get hyperlink for
2683
     */
2684 View Code Duplication
    public function getHyperlink($pCellCoordinate = 'A1')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2685
    {
2686
        // return hyperlink if we already have one
2687
        if (isset($this->hyperlinkCollection[$pCellCoordinate])) {
2688
            return $this->hyperlinkCollection[$pCellCoordinate];
2689
        }
2690
2691
        // else create hyperlink
2692
        $this->hyperlinkCollection[$pCellCoordinate] = new Cell\Hyperlink();
2693
        return $this->hyperlinkCollection[$pCellCoordinate];
2694
    }
2695
2696
    /**
2697
     * Set hyperlnk
2698
     *
2699
     * @param string $pCellCoordinate    Cell coordinate to insert hyperlink
2700
     * @param    Cell\Hyperlink    $pHyperlink
2701
     * @return Worksheet
2702
     */
2703
    public function setHyperlink($pCellCoordinate = 'A1', Cell\Hyperlink $pHyperlink = null)
2704
    {
2705
        if ($pHyperlink === null) {
2706
            unset($this->hyperlinkCollection[$pCellCoordinate]);
2707
        } else {
2708
            $this->hyperlinkCollection[$pCellCoordinate] = $pHyperlink;
2709
        }
2710
        return $this;
2711
    }
2712
2713
    /**
2714
     * Hyperlink at a specific coordinate exists?
2715
     *
2716
     * @param string $pCoordinate
2717
     * @return boolean
2718
     */
2719
    public function hyperlinkExists($pCoordinate = 'A1')
2720
    {
2721
        return isset($this->hyperlinkCollection[$pCoordinate]);
2722
    }
2723
2724
    /**
2725
     * Get collection of hyperlinks
2726
     *
2727
     * @return Cell\Hyperlink[]
2728
     */
2729
    public function getHyperlinkCollection()
2730
    {
2731
        return $this->hyperlinkCollection;
2732
    }
2733
2734
    /**
2735
     * Get data validation
2736
     *
2737
     * @param string $pCellCoordinate Cell coordinate to get data validation for
2738
     */
2739 View Code Duplication
    public function getDataValidation($pCellCoordinate = 'A1')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
2740
    {
2741
        // return data validation if we already have one
2742
        if (isset($this->dataValidationCollection[$pCellCoordinate])) {
2743
            return $this->dataValidationCollection[$pCellCoordinate];
2744
        }
2745
2746
        // else create data validation
2747
        $this->dataValidationCollection[$pCellCoordinate] = new Cell\DataValidation();
2748
        return $this->dataValidationCollection[$pCellCoordinate];
2749
    }
2750
2751
    /**
2752
     * Set data validation
2753
     *
2754
     * @param string $pCellCoordinate    Cell coordinate to insert data validation
2755
     * @param    Cell\DataValidation    $pDataValidation
2756
     * @return Worksheet
2757
     */
2758
    public function setDataValidation($pCellCoordinate = 'A1', Cell\DataValidation $pDataValidation = null)
2759
    {
2760
        if ($pDataValidation === null) {
2761
            unset($this->dataValidationCollection[$pCellCoordinate]);
2762
        } else {
2763
            $this->dataValidationCollection[$pCellCoordinate] = $pDataValidation;
2764
        }
2765
        return $this;
2766
    }
2767
2768
    /**
2769
     * Data validation at a specific coordinate exists?
2770
     *
2771
     * @param string $pCoordinate
2772
     * @return boolean
2773
     */
2774
    public function dataValidationExists($pCoordinate = 'A1')
2775
    {
2776
        return isset($this->dataValidationCollection[$pCoordinate]);
2777
    }
2778
2779
    /**
2780
     * Get collection of data validations
2781
     *
2782
     * @return Cell\DataValidation[]
2783
     */
2784
    public function getDataValidationCollection()
2785
    {
2786
        return $this->dataValidationCollection;
2787
    }
2788
2789
    /**
2790
     * Accepts a range, returning it as a range that falls within the current highest row and column of the worksheet
2791
     *
2792
     * @param string $range
2793
     * @return string Adjusted range value
2794
     */
2795
    public function shrinkRangeToFit($range)
2796
    {
2797
        $maxCol = $this->getHighestColumn();
2798
        $maxRow = $this->getHighestRow();
2799
        $maxCol = Cell::columnIndexFromString($maxCol);
2800
2801
        $rangeBlocks = explode(' ', $range);
2802
        foreach ($rangeBlocks as &$rangeSet) {
2803
            $rangeBoundaries = Cell::getRangeBoundaries($rangeSet);
2804
2805 View Code Duplication
            if (Cell::columnIndexFromString($rangeBoundaries[0][0]) > $maxCol) {
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...
2806
                $rangeBoundaries[0][0] = Cell::stringFromColumnIndex($maxCol);
2807
            }
2808
            if ($rangeBoundaries[0][1] > $maxRow) {
2809
                $rangeBoundaries[0][1] = $maxRow;
2810
            }
2811 View Code Duplication
            if (Cell::columnIndexFromString($rangeBoundaries[1][0]) > $maxCol) {
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...
2812
                $rangeBoundaries[1][0] = Cell::stringFromColumnIndex($maxCol);
2813
            }
2814
            if ($rangeBoundaries[1][1] > $maxRow) {
2815
                $rangeBoundaries[1][1] = $maxRow;
2816
            }
2817
            $rangeSet = $rangeBoundaries[0][0].$rangeBoundaries[0][1].':'.$rangeBoundaries[1][0].$rangeBoundaries[1][1];
2818
        }
2819
        unset($rangeSet);
2820
        $stRange = implode(' ', $rangeBlocks);
2821
2822
        return $stRange;
2823
    }
2824
2825
    /**
2826
     * Get tab color
2827
     *
2828
     * @return Style\Color
2829
     */
2830
    public function getTabColor()
2831
    {
2832
        if ($this->tabColor === null) {
2833
            $this->tabColor = new Style\Color();
2834
        }
2835
        return $this->tabColor;
2836
    }
2837
2838
    /**
2839
     * Reset tab color
2840
     *
2841
     * @return Worksheet
2842
     */
2843
    public function resetTabColor()
2844
    {
2845
        $this->tabColor = null;
2846
        unset($this->tabColor);
2847
2848
        return $this;
2849
    }
2850
2851
    /**
2852
     * Tab color set?
2853
     *
2854
     * @return boolean
2855
     */
2856
    public function isTabColorSet()
2857
    {
2858
        return ($this->tabColor !== null);
2859
    }
2860
2861
    /**
2862
     * Copy worksheet (!= clone!)
2863
     *
2864
     * @return Worksheet
2865
     */
2866
    public function copy()
2867
    {
2868
        $copied = clone $this;
2869
2870
        return $copied;
2871
    }
2872
2873
    /**
2874
     * Implement PHP __clone to create a deep clone, not just a shallow copy.
2875
     */
2876
    public function __clone()
2877
    {
2878
        foreach ($this as $key => $val) {
0 ignored issues
show
Bug introduced by
The expression $this of type this<PhpSpreadsheet\Worksheet> is not traversable.
Loading history...
2879
            if ($key == 'parent') {
2880
                continue;
2881
            }
2882
2883
            if (is_object($val) || (is_array($val))) {
2884
                if ($key == 'cellCollection') {
2885
                    $newCollection = clone $this->cellCollection;
2886
                    $newCollection->copyCellCollection($this);
2887
                    $this->cellCollection = $newCollection;
2888
                } elseif ($key == 'drawingCollection') {
2889
                    $newCollection = clone $this->drawingCollection;
2890
                    $this->drawingCollection = $newCollection;
0 ignored issues
show
Documentation Bug introduced by
It seems like $newCollection can also be of type object. However, the property $drawingCollection is declared as type array<integer,object<Php...Worksheet\BaseDrawing>>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
2891
                } elseif (($key == 'autoFilter') && ($this->autoFilter instanceof Worksheet\AutoFilter)) {
2892
                    $newAutoFilter = clone $this->autoFilter;
2893
                    $this->autoFilter = $newAutoFilter;
2894
                    $this->autoFilter->setParent($this);
2895
                } else {
2896
                    $this->{$key} = unserialize(serialize($val));
2897
                }
2898
            }
2899
        }
2900
    }
2901
/**
2902
     * Define the code name of the sheet
2903
     *
2904
     * @param null|string Same rule as Title minus space not allowed (but, like Excel, change silently space to underscore)
2905
     * @return objWorksheet
2906
     * @throws Exception
2907
    */
2908
    public function setCodeName($pValue = null)
2909
    {
2910
        // Is this a 'rename' or not?
2911
        if ($this->getCodeName() == $pValue) {
2912
            return $this;
2913
        }
2914
        $pValue = str_replace(' ', '_', $pValue);//Excel does this automatically without flinching, we are doing the same
2915
        // Syntax check
2916
        // throw an exception if not valid
2917
        self::checkSheetCodeName($pValue);
2918
2919
        // We use the same code that setTitle to find a valid codeName else not using a space (Excel don't like) but a '_'
2920
2921
        if ($this->getParent()) {
2922
            // Is there already such sheet name?
2923
            if ($this->getParent()->sheetCodeNameExists($pValue)) {
2924
                // Use name, but append with lowest possible integer
2925
2926
                if (Shared\StringHelper::countCharacters($pValue) > 29) {
2927
                    $pValue = Shared\StringHelper::substring($pValue, 0, 29);
2928
                }
2929
                $i = 1;
2930 View Code Duplication
                while ($this->getParent()->sheetCodeNameExists($pValue . '_' . $i)) {
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...
2931
                    ++$i;
2932
                    if ($i == 10) {
2933
                        if (Shared\StringHelper::countCharacters($pValue) > 28) {
2934
                            $pValue = Shared\StringHelper::substring($pValue, 0, 28);
2935
                        }
2936
                    } elseif ($i == 100) {
2937
                        if (Shared\StringHelper::countCharacters($pValue) > 27) {
2938
                            $pValue = Shared\StringHelper::substring($pValue, 0, 27);
2939
                        }
2940
                    }
2941
                }
2942
2943
                $pValue = $pValue . '_' . $i;// ok, we have a valid name
2944
                //codeName is'nt used in formula : no need to call for an update
2945
                //return $this->setTitle($altTitle, $updateFormulaCellReferences);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
2946
            }
2947
        }
2948
2949
        $this->codeName=$pValue;
2950
        return $this;
2951
    }
2952
    /**
2953
     * Return the code name of the sheet
2954
     *
2955
     * @return null|string
2956
    */
2957
    public function getCodeName()
2958
    {
2959
        return $this->codeName;
2960
    }
2961
    /**
2962
     * Sheet has a code name ?
2963
     * @return boolean
2964
    */
2965
    public function hasCodeName()
2966
    {
2967
        return !(is_null($this->codeName));
2968
    }
2969
}
2970