Passed
Push — master ( 10b137...2bffcf )
by Adrien
10:25
created

Spreadsheet   F

Complexity

Total Complexity 191

Size/Duplication

Total Lines 1581
Duplicated Lines 0 %

Test Coverage

Coverage 76.8%

Importance

Changes 5
Bugs 0 Features 0
Metric Value
eloc 373
dl 0
loc 1581
ccs 341
cts 444
cp 0.768
rs 2
c 5
b 0
f 0
wmc 191

91 Methods

Rating   Name   Duplication   Size   Complexity  
A setUnparsedLoadedData() 0 3 1
A setSecurity() 0 3 1
A getSheetCount() 0 3 1
A getActiveSheetIndex() 0 3 1
A getSheetNames() 0 9 2
A getActiveSheet() 0 3 1
A createSheet() 0 6 1
A sheetNameExists() 0 3 1
A getMacrosCertificate() 0 3 1
A hasMacrosCertificate() 0 3 1
A getSheetByCodeName() 0 10 3
A getProperties() 0 3 1
A __construct() 0 26 1
A hasMacros() 0 3 1
A getSecurity() 0 3 1
A getCalculationEngine() 0 3 1
A hasRibbon() 0 3 1
B getRibbonBinObjects() 0 31 10
A discardMacros() 0 5 1
A hasRibbonBinObjects() 0 3 1
A getMacrosCode() 0 3 1
A setMacrosCertificate() 0 3 1
A setRibbonXMLData() 0 6 3
A sheetCodeNameExists() 0 3 1
A setHasMacros() 0 3 1
A setMacrosCode() 0 4 1
A addNamedRange() 0 3 1
A removeDefinedName() 0 17 5
A getLocalDefinedNameByType() 0 10 4
A getAllSheets() 0 3 1
A getDefinedNames() 0 3 1
A removeNamedRange() 0 7 2
A addDefinedName() 0 9 2
A getNamedRange() 0 13 4
A getSheetByName() 0 10 3
A removeNamedFormula() 0 7 2
A getDefinedName() 0 18 5
A getGlobalDefinedNameByType() 0 7 3
A getNamedFormula() 0 13 4
A addNamedFormula() 0 3 1
A setProperties() 0 3 1
A getWorksheetIterator() 0 3 1
A copy() 0 11 2
A removeCellStyleXfByIndex() 0 6 2
A addCellXf() 0 4 1
A getCellStyleXfCollection() 0 3 1
A getCellStyleXfByHashCode() 0 9 3
A getCellXfCollection() 0 3 1
A cellXfExists() 0 3 1
A getCellXfByHashCode() 0 9 3
A getDefaultStyle() 0 7 2
A getCellXfSupervisor() 0 3 1
A setShowVerticalScroll() 0 3 1
A setShowHorizontalScroll() 0 3 1
A setAutoFilterDateGrouping() 0 3 1
A setShowSheetTabs() 0 3 1
A setMinimized() 0 3 1
A getShowHorizontalScroll() 0 3 1
A getVisibility() 0 3 1
A setFirstSheetIndex() 0 6 2
A getShowSheetTabs() 0 3 1
A getTabRatio() 0 3 1
F garbageCollect() 0 74 17
A getID() 0 3 1
A setTabRatio() 0 6 3
A getAutoFilterDateGrouping() 0 3 1
A getShowVerticalScroll() 0 3 1
A getFirstSheetIndex() 0 3 1
A setVisibility() 0 10 3
A getMinimized() 0 3 1
A getExtensionOnly() 0 5 2
A getUnparsedLoadedData() 0 3 1
A setRibbonBinObjects() 0 6 3
A getRibbonXMLData() 0 19 6
A disconnectWorksheets() 0 7 2
A __destruct() 0 6 1
A addCellStyleXf() 0 4 1
A getCellStyleXfByIndex() 0 3 1
A removeSheetByIndex() 0 16 5
A setIndexByName() 0 16 1
A getSheet() 0 11 2
A __clone() 0 6 4
A getIndex() 0 9 3
A addExternalSheet() 0 24 4
A getCellXfByIndex() 0 3 1
A setActiveSheetIndex() 0 12 2
A addSheet() 0 33 6
A removeCellXfByIndex() 0 20 6
A setActiveSheetIndexByName() 0 9 2
A getNamedFormulae() 0 6 1
A getNamedRanges() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like Spreadsheet 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.

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 Spreadsheet, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet;
4
5
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
6
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
7
use PhpOffice\PhpSpreadsheet\Style\Style;
8
use PhpOffice\PhpSpreadsheet\Worksheet\Iterator;
9
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
10
11
class Spreadsheet
12
{
13
    // Allowable values for workbook window visilbity
14
    const VISIBILITY_VISIBLE = 'visible';
15
    const VISIBILITY_HIDDEN = 'hidden';
16
    const VISIBILITY_VERY_HIDDEN = 'veryHidden';
17
18
    private const DEFINED_NAME_IS_RANGE = false;
19
    private const DEFINED_NAME_IS_FORMULA = true;
20
21
    private static $workbookViewVisibilityValues = [
22
        self::VISIBILITY_VISIBLE,
23
        self::VISIBILITY_HIDDEN,
24
        self::VISIBILITY_VERY_HIDDEN,
25
    ];
26
27
    /**
28
     * Unique ID.
29
     *
30
     * @var string
31
     */
32
    private $uniqueID;
33
34
    /**
35
     * Document properties.
36
     *
37
     * @var Document\Properties
38
     */
39
    private $properties;
40
41
    /**
42
     * Document security.
43
     *
44
     * @var Document\Security
45
     */
46
    private $security;
47
48
    /**
49
     * Collection of Worksheet objects.
50
     *
51
     * @var Worksheet[]
52
     */
53
    private $workSheetCollection = [];
54
55
    /**
56
     * Calculation Engine.
57
     *
58
     * @var null|Calculation
59
     */
60
    private $calculationEngine;
61
62
    /**
63
     * Active sheet index.
64
     *
65
     * @var int
66
     */
67
    private $activeSheetIndex = 0;
68
69
    /**
70
     * Named ranges.
71
     *
72
     * @var DefinedName[]
73
     */
74
    private $definedNames = [];
75
76
    /**
77
     * CellXf supervisor.
78
     *
79
     * @var Style
80
     */
81
    private $cellXfSupervisor;
82
83
    /**
84
     * CellXf collection.
85
     *
86
     * @var Style[]
87
     */
88
    private $cellXfCollection = [];
89
90
    /**
91
     * CellStyleXf collection.
92
     *
93
     * @var Style[]
94
     */
95
    private $cellStyleXfCollection = [];
96
97
    /**
98
     * hasMacros : this workbook have macros ?
99
     *
100
     * @var bool
101
     */
102
    private $hasMacros = false;
103
104
    /**
105
     * macrosCode : all macros code as binary data (the vbaProject.bin file, this include form, code,  etc.), null if no macro.
106
     *
107
     * @var null|string
108
     */
109
    private $macrosCode;
110
111
    /**
112
     * macrosCertificate : if macros are signed, contains binary data vbaProjectSignature.bin file, null if not signed.
113
     *
114
     * @var null|string
115
     */
116
    private $macrosCertificate;
117
118
    /**
119
     * ribbonXMLData : null if workbook is'nt Excel 2007 or not contain a customized UI.
120
     *
121
     * @var null|array{target: string, data: string}
122
     */
123
    private $ribbonXMLData;
124
125
    /**
126
     * ribbonBinObjects : null if workbook is'nt Excel 2007 or not contain embedded objects (picture(s)) for Ribbon Elements
127
     * ignored if $ribbonXMLData is null.
128
     *
129
     * @var null|array
130
     */
131
    private $ribbonBinObjects;
132
133
    /**
134
     * List of unparsed loaded data for export to same format with better compatibility.
135
     * It has to be minimized when the library start to support currently unparsed data.
136
     *
137
     * @var array
138
     */
139
    private $unparsedLoadedData = [];
140
141
    /**
142
     * Controls visibility of the horizonal scroll bar in the application.
143
     *
144
     * @var bool
145
     */
146
    private $showHorizontalScroll = true;
147
148
    /**
149
     * Controls visibility of the horizonal scroll bar in the application.
150
     *
151
     * @var bool
152
     */
153
    private $showVerticalScroll = true;
154
155
    /**
156
     * Controls visibility of the sheet tabs in the application.
157
     *
158
     * @var bool
159
     */
160
    private $showSheetTabs = true;
161
162
    /**
163
     * Specifies a boolean value that indicates whether the workbook window
164
     * is minimized.
165
     *
166
     * @var bool
167
     */
168
    private $minimized = false;
169
170
    /**
171
     * Specifies a boolean value that indicates whether to group dates
172
     * when presenting the user with filtering optiomd in the user
173
     * interface.
174
     *
175
     * @var bool
176
     */
177
    private $autoFilterDateGrouping = true;
178
179
    /**
180
     * Specifies the index to the first sheet in the book view.
181
     *
182
     * @var int
183
     */
184
    private $firstSheetIndex = 0;
185
186
    /**
187
     * Specifies the visible status of the workbook.
188
     *
189
     * @var string
190
     */
191
    private $visibility = self::VISIBILITY_VISIBLE;
192
193
    /**
194
     * Specifies the ratio between the workbook tabs bar and the horizontal
195
     * scroll bar.  TabRatio is assumed to be out of 1000 of the horizontal
196
     * window width.
197
     *
198
     * @var int
199
     */
200
    private $tabRatio = 600;
201
202
    /**
203
     * The workbook has macros ?
204
     *
205
     * @return bool
206
     */
207 160
    public function hasMacros()
208
    {
209 160
        return $this->hasMacros;
210
    }
211
212
    /**
213
     * Define if a workbook has macros.
214
     *
215
     * @param bool $hasMacros true|false
216
     */
217 1
    public function setHasMacros($hasMacros): void
218
    {
219 1
        $this->hasMacros = (bool) $hasMacros;
220 1
    }
221
222
    /**
223
     * Set the macros code.
224
     *
225
     * @param string $macroCode string|null
226
     */
227 1
    public function setMacrosCode($macroCode): void
228
    {
229 1
        $this->macrosCode = $macroCode;
230 1
        $this->setHasMacros($macroCode !== null);
231 1
    }
232
233
    /**
234
     * Return the macros code.
235
     *
236
     * @return null|string
237
     */
238 1
    public function getMacrosCode()
239
    {
240 1
        return $this->macrosCode;
241
    }
242
243
    /**
244
     * Set the macros certificate.
245
     *
246
     * @param null|string $certificate
247
     */
248
    public function setMacrosCertificate($certificate): void
249
    {
250
        $this->macrosCertificate = $certificate;
251
    }
252
253
    /**
254
     * Is the project signed ?
255
     *
256
     * @return bool true|false
257
     */
258 1
    public function hasMacrosCertificate()
259
    {
260 1
        return $this->macrosCertificate !== null;
261
    }
262
263
    /**
264
     * Return the macros certificate.
265
     *
266
     * @return null|string
267
     */
268
    public function getMacrosCertificate()
269
    {
270
        return $this->macrosCertificate;
271
    }
272
273
    /**
274
     * Remove all macros, certificate from spreadsheet.
275
     */
276
    public function discardMacros(): void
277
    {
278
        $this->hasMacros = false;
279
        $this->macrosCode = null;
280
        $this->macrosCertificate = null;
281
    }
282
283
    /**
284
     * set ribbon XML data.
285
     *
286
     * @param null|mixed $target
287
     * @param null|mixed $xmlData
288
     */
289
    public function setRibbonXMLData($target, $xmlData): void
290
    {
291
        if ($target !== null && $xmlData !== null) {
292
            $this->ribbonXMLData = ['target' => $target, 'data' => $xmlData];
293
        } else {
294
            $this->ribbonXMLData = null;
295
        }
296
    }
297
298
    /**
299
     * retrieve ribbon XML Data.
300
     *
301
     * @param string $what
302
     *
303
     * @return null|array|string
304
     */
305
    public function getRibbonXMLData($what = 'all') //we need some constants here...
306
    {
307
        $returnData = null;
308
        $what = strtolower($what);
309
        switch ($what) {
310
            case 'all':
311
                $returnData = $this->ribbonXMLData;
312
313
                break;
314
            case 'target':
315
            case 'data':
316
                if (is_array($this->ribbonXMLData) && isset($this->ribbonXMLData[$what])) {
317
                    $returnData = $this->ribbonXMLData[$what];
318
                }
319
320
                break;
321
        }
322
323
        return $returnData;
324
    }
325
326
    /**
327
     * store binaries ribbon objects (pictures).
328
     *
329
     * @param null|mixed $BinObjectsNames
330
     * @param null|mixed $BinObjectsData
331
     */
332
    public function setRibbonBinObjects($BinObjectsNames, $BinObjectsData): void
333
    {
334
        if ($BinObjectsNames !== null && $BinObjectsData !== null) {
335
            $this->ribbonBinObjects = ['names' => $BinObjectsNames, 'data' => $BinObjectsData];
336
        } else {
337
            $this->ribbonBinObjects = null;
338
        }
339
    }
340
341
    /**
342
     * List of unparsed loaded data for export to same format with better compatibility.
343
     * It has to be minimized when the library start to support currently unparsed data.
344
     *
345
     * @internal
346
     *
347
     * @return array
348
     */
349 160
    public function getUnparsedLoadedData()
350
    {
351 160
        return $this->unparsedLoadedData;
352
    }
353
354
    /**
355
     * List of unparsed loaded data for export to same format with better compatibility.
356
     * It has to be minimized when the library start to support currently unparsed data.
357
     *
358
     * @internal
359
     */
360 176
    public function setUnparsedLoadedData(array $unparsedLoadedData): void
361
    {
362 176
        $this->unparsedLoadedData = $unparsedLoadedData;
363 176
    }
364
365
    /**
366
     * return the extension of a filename. Internal use for a array_map callback (php<5.3 don't like lambda function).
367
     *
368
     * @param mixed $path
369
     *
370
     * @return string
371
     */
372
    private function getExtensionOnly($path)
373
    {
374
        $extension = pathinfo($path, PATHINFO_EXTENSION);
375
376
        return is_array($extension) ? '' : $extension;
377
    }
378
379
    /**
380
     * retrieve Binaries Ribbon Objects.
381
     *
382
     * @param string $what
383
     *
384
     * @return null|array
385
     */
386
    public function getRibbonBinObjects($what = 'all')
387
    {
388
        $ReturnData = null;
389
        $what = strtolower($what);
390
        switch ($what) {
391
            case 'all':
392
                return $this->ribbonBinObjects;
393
394
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
395
            case 'names':
396
            case 'data':
397
                if (is_array($this->ribbonBinObjects) && isset($this->ribbonBinObjects[$what])) {
398
                    $ReturnData = $this->ribbonBinObjects[$what];
399
                }
400
401
                break;
402
            case 'types':
403
                if (
404
                    is_array($this->ribbonBinObjects) &&
405
                    isset($this->ribbonBinObjects['data']) && is_array($this->ribbonBinObjects['data'])
406
                ) {
407
                    $tmpTypes = array_keys($this->ribbonBinObjects['data']);
408
                    $ReturnData = array_unique(array_map([$this, 'getExtensionOnly'], $tmpTypes));
409
                } else {
410
                    $ReturnData = []; // the caller want an array... not null if empty
411
                }
412
413
                break;
414
        }
415
416
        return $ReturnData;
417
    }
418
419
    /**
420
     * This workbook have a custom UI ?
421
     *
422
     * @return bool
423
     */
424 159
    public function hasRibbon()
425
    {
426 159
        return $this->ribbonXMLData !== null;
427
    }
428
429
    /**
430
     * This workbook have additionnal object for the ribbon ?
431
     *
432
     * @return bool
433
     */
434 159
    public function hasRibbonBinObjects()
435
    {
436 159
        return $this->ribbonBinObjects !== null;
437
    }
438
439
    /**
440
     * Check if a sheet with a specified code name already exists.
441
     *
442
     * @param string $codeName Name of the worksheet to check
443
     *
444
     * @return bool
445
     */
446 4816
    public function sheetCodeNameExists($codeName)
447
    {
448 4816
        return $this->getSheetByCodeName($codeName) !== null;
449
    }
450
451
    /**
452
     * Get sheet by code name. Warning : sheet don't have always a code name !
453
     *
454
     * @param string $codeName Sheet name
455
     *
456
     * @return null|Worksheet
457
     */
458 4816
    public function getSheetByCodeName($codeName)
459
    {
460 4816
        $worksheetCount = count($this->workSheetCollection);
461 4816
        for ($i = 0; $i < $worksheetCount; ++$i) {
462 307
            if ($this->workSheetCollection[$i]->getCodeName() == $codeName) {
463 197
                return $this->workSheetCollection[$i];
464
            }
465
        }
466
467 4816
        return null;
468
    }
469
470
    /**
471
     * Create a new PhpSpreadsheet with one Worksheet.
472
     */
473 4816
    public function __construct()
474
    {
475 4816
        $this->uniqueID = uniqid('', true);
476 4816
        $this->calculationEngine = new Calculation($this);
477
478
        // Initialise worksheet collection and add one worksheet
479 4816
        $this->workSheetCollection = [];
480 4816
        $this->workSheetCollection[] = new Worksheet($this);
481 4816
        $this->activeSheetIndex = 0;
482
483
        // Create document properties
484 4816
        $this->properties = new Document\Properties();
485
486
        // Create document security
487 4816
        $this->security = new Document\Security();
488
489
        // Set defined names
490 4816
        $this->definedNames = [];
491
492
        // Create the cellXf supervisor
493 4816
        $this->cellXfSupervisor = new Style(true);
494 4816
        $this->cellXfSupervisor->bindParent($this);
495
496
        // Create the default style
497 4816
        $this->addCellXf(new Style());
498 4816
        $this->addCellStyleXf(new Style());
499 4816
    }
500
501
    /**
502
     * Code to execute when this worksheet is unset().
503
     */
504 35
    public function __destruct()
505
    {
506 35
        $this->disconnectWorksheets();
507 35
        $this->calculationEngine = null;
508 35
        $this->cellXfCollection = [];
509 35
        $this->cellStyleXfCollection = [];
510 35
    }
511
512
    /**
513
     * Disconnect all worksheets from this PhpSpreadsheet workbook object,
514
     * typically so that the PhpSpreadsheet object can be unset.
515
     */
516 3107
    public function disconnectWorksheets(): void
517
    {
518 3107
        foreach ($this->workSheetCollection as $worksheet) {
519 3105
            $worksheet->disconnectCells();
520 3105
            unset($worksheet);
521
        }
522 3107
        $this->workSheetCollection = [];
523 3107
    }
524
525
    /**
526
     * Return the calculation engine for this worksheet.
527
     *
528
     * @return null|Calculation
529
     */
530 4816
    public function getCalculationEngine()
531
    {
532 4816
        return $this->calculationEngine;
533
    }
534
535
    /**
536
     * Get properties.
537
     *
538
     * @return Document\Properties
539
     */
540 526
    public function getProperties()
541
    {
542 526
        return $this->properties;
543
    }
544
545
    /**
546
     * Set properties.
547
     */
548
    public function setProperties(Document\Properties $documentProperties): void
549
    {
550
        $this->properties = $documentProperties;
551
    }
552
553
    /**
554
     * Get security.
555
     *
556
     * @return Document\Security
557
     */
558 160
    public function getSecurity()
559
    {
560 160
        return $this->security;
561
    }
562
563
    /**
564
     * Set security.
565
     */
566
    public function setSecurity(Document\Security $documentSecurity): void
567
    {
568
        $this->security = $documentSecurity;
569
    }
570
571
    /**
572
     * Get active sheet.
573
     *
574
     * @return Worksheet
575
     */
576 4778
    public function getActiveSheet()
577
    {
578 4778
        return $this->getSheet($this->activeSheetIndex);
579
    }
580
581
    /**
582
     * Create sheet and add it to this workbook.
583
     *
584
     * @param null|int $sheetIndex Index where sheet should go (0,1,..., or null for last)
585
     *
586
     * @return Worksheet
587
     */
588 449
    public function createSheet($sheetIndex = null)
589
    {
590 449
        $newSheet = new Worksheet($this);
591 449
        $this->addSheet($newSheet, $sheetIndex);
592
593 449
        return $newSheet;
594
    }
595
596
    /**
597
     * Check if a sheet with a specified name already exists.
598
     *
599
     * @param string $worksheetName Name of the worksheet to check
600
     *
601
     * @return bool
602
     */
603 4816
    public function sheetNameExists($worksheetName)
604
    {
605 4816
        return $this->getSheetByName($worksheetName) !== null;
606
    }
607
608
    /**
609
     * Add sheet.
610
     *
611
     * @param Worksheet $worksheet The worskeet to add
612
     * @param null|int $sheetIndex Index where sheet should go (0,1,..., or null for last)
613
     *
614
     * @return Worksheet
615
     */
616 522
    public function addSheet(Worksheet $worksheet, $sheetIndex = null)
617
    {
618 522
        if ($this->sheetNameExists($worksheet->getTitle())) {
619 1
            throw new Exception(
620 1
                "Workbook already contains a worksheet named '{$worksheet->getTitle()}'. Rename this worksheet first."
621
            );
622
        }
623
624 522
        if ($sheetIndex === null) {
625 493
            if ($this->activeSheetIndex < 0) {
626 254
                $this->activeSheetIndex = 0;
627
            }
628 493
            $this->workSheetCollection[] = $worksheet;
629
        } else {
630
            // Insert the sheet at the requested index
631 32
            array_splice(
632 32
                $this->workSheetCollection,
633
                $sheetIndex,
634 32
                0,
635 32
                [$worksheet]
636
            );
637
638
            // Adjust active sheet index if necessary
639 32
            if ($this->activeSheetIndex >= $sheetIndex) {
640 28
                ++$this->activeSheetIndex;
641
            }
642
        }
643
644 522
        if ($worksheet->getParent() === null) {
645 45
            $worksheet->rebindParent($this);
646
        }
647
648 522
        return $worksheet;
649
    }
650
651
    /**
652
     * Remove sheet by index.
653
     *
654
     * @param int $sheetIndex Index position of the worksheet to remove
655
     */
656 263
    public function removeSheetByIndex($sheetIndex): void
657
    {
658 263
        $numSheets = count($this->workSheetCollection);
659 263
        if ($sheetIndex > $numSheets - 1) {
660 1
            throw new Exception(
661 1
                "You tried to remove a sheet by the out of bounds index: {$sheetIndex}. The actual number of sheets is {$numSheets}."
662
            );
663
        }
664 262
        array_splice($this->workSheetCollection, $sheetIndex, 1);
665
666
        // Adjust active sheet index if necessary
667
        if (
668 262
            ($this->activeSheetIndex >= $sheetIndex) &&
669 262
            ($this->activeSheetIndex > 0 || $numSheets <= 1)
670
        ) {
671 260
            --$this->activeSheetIndex;
672
        }
673 262
    }
674
675
    /**
676
     * Get sheet by index.
677
     *
678
     * @param int $sheetIndex Sheet index
679
     *
680
     * @return Worksheet
681
     */
682 4794
    public function getSheet($sheetIndex)
683
    {
684 4794
        if (!isset($this->workSheetCollection[$sheetIndex])) {
685 1
            $numSheets = $this->getSheetCount();
686
687 1
            throw new Exception(
688 1
                "Your requested sheet index: {$sheetIndex} is out of bounds. The actual number of sheets is {$numSheets}."
689
            );
690
        }
691
692 4794
        return $this->workSheetCollection[$sheetIndex];
693
    }
694
695
    /**
696
     * Get all sheets.
697
     *
698
     * @return Worksheet[]
699
     */
700 94
    public function getAllSheets()
701
    {
702 94
        return $this->workSheetCollection;
703
    }
704
705
    /**
706
     * Get sheet by name.
707
     *
708
     * @param string $worksheetName Sheet name
709
     *
710
     * @return null|Worksheet
711
     */
712 4816
    public function getSheetByName($worksheetName)
713
    {
714 4816
        $worksheetCount = count($this->workSheetCollection);
715 4816
        for ($i = 0; $i < $worksheetCount; ++$i) {
716 4344
            if ($this->workSheetCollection[$i]->getTitle() === trim($worksheetName, "'")) {
717 4131
                return $this->workSheetCollection[$i];
718
            }
719
        }
720
721 4816
        return null;
722
    }
723
724
    /**
725
     * Get index for sheet.
726
     *
727
     * @return int index
728
     */
729 4459
    public function getIndex(Worksheet $worksheet)
730
    {
731 4459
        foreach ($this->workSheetCollection as $key => $value) {
732 4459
            if ($value->getHashCode() === $worksheet->getHashCode()) {
733 4458
                return $key;
734
            }
735
        }
736
737 2
        throw new Exception('Sheet does not exist.');
738
    }
739
740
    /**
741
     * Set index for sheet by sheet name.
742
     *
743
     * @param string $worksheetName Sheet name to modify index for
744
     * @param int $newIndexPosition New index for the sheet
745
     *
746
     * @return int New sheet index
747
     */
748 1
    public function setIndexByName($worksheetName, $newIndexPosition)
749
    {
750 1
        $oldIndex = $this->getIndex($this->getSheetByName($worksheetName));
1 ignored issue
show
Bug introduced by
It seems like $this->getSheetByName($worksheetName) can also be of type null; however, parameter $worksheet of PhpOffice\PhpSpreadsheet\Spreadsheet::getIndex() does only seem to accept PhpOffice\PhpSpreadsheet\Worksheet\Worksheet, maybe add an additional type check? ( Ignorable by Annotation )

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

750
        $oldIndex = $this->getIndex(/** @scrutinizer ignore-type */ $this->getSheetByName($worksheetName));
Loading history...
751 1
        $worksheet = array_splice(
752 1
            $this->workSheetCollection,
753
            $oldIndex,
754 1
            1
755
        );
756 1
        array_splice(
757 1
            $this->workSheetCollection,
758
            $newIndexPosition,
759 1
            0,
760
            $worksheet
761
        );
762
763 1
        return $newIndexPosition;
764
    }
765
766
    /**
767
     * Get sheet count.
768
     *
769
     * @return int
770
     */
771 681
    public function getSheetCount()
772
    {
773 681
        return count($this->workSheetCollection);
774
    }
775
776
    /**
777
     * Get active sheet index.
778
     *
779
     * @return int Active sheet index
780
     */
781 4158
    public function getActiveSheetIndex()
782
    {
783 4158
        return $this->activeSheetIndex;
784
    }
785
786
    /**
787
     * Set active sheet index.
788
     *
789
     * @param int $worksheetIndex Active sheet index
790
     *
791
     * @return Worksheet
792
     */
793 4577
    public function setActiveSheetIndex($worksheetIndex)
794
    {
795 4577
        $numSheets = count($this->workSheetCollection);
796
797 4577
        if ($worksheetIndex > $numSheets - 1) {
798 1
            throw new Exception(
799 1
                "You tried to set a sheet active by the out of bounds index: {$worksheetIndex}. The actual number of sheets is {$numSheets}."
800
            );
801
        }
802 4576
        $this->activeSheetIndex = $worksheetIndex;
803
804 4576
        return $this->getActiveSheet();
805
    }
806
807
    /**
808
     * Set active sheet index by name.
809
     *
810
     * @param string $worksheetName Sheet title
811
     *
812
     * @return Worksheet
813
     */
814 64
    public function setActiveSheetIndexByName($worksheetName)
815
    {
816 64
        if (($worksheet = $this->getSheetByName($worksheetName)) instanceof Worksheet) {
817 62
            $this->setActiveSheetIndex($this->getIndex($worksheet));
818
819 62
            return $worksheet;
820
        }
821
822 2
        throw new Exception('Workbook does not contain sheet:' . $worksheetName);
823
    }
824
825
    /**
826
     * Get sheet names.
827
     *
828
     * @return string[]
829
     */
830 9
    public function getSheetNames()
831
    {
832 9
        $returnValue = [];
833 9
        $worksheetCount = $this->getSheetCount();
834 9
        for ($i = 0; $i < $worksheetCount; ++$i) {
835 9
            $returnValue[] = $this->getSheet($i)->getTitle();
836
        }
837
838 9
        return $returnValue;
839
    }
840
841
    /**
842
     * Add external sheet.
843
     *
844
     * @param Worksheet $worksheet External sheet to add
845
     * @param null|int $sheetIndex Index where sheet should go (0,1,..., or null for last)
846
     *
847
     * @return Worksheet
848
     */
849 3
    public function addExternalSheet(Worksheet $worksheet, $sheetIndex = null)
850
    {
851 3
        if ($this->sheetNameExists($worksheet->getTitle())) {
852 1
            throw new Exception("Workbook already contains a worksheet named '{$worksheet->getTitle()}'. Rename the external sheet first.");
853
        }
854
855
        // count how many cellXfs there are in this workbook currently, we will need this below
856 2
        $countCellXfs = count($this->cellXfCollection);
857
858
        // copy all the shared cellXfs from the external workbook and append them to the current
859 2
        foreach ($worksheet->getParent()->getCellXfCollection() as $cellXf) {
860 2
            $this->addCellXf(clone $cellXf);
861
        }
862
863
        // move sheet to this workbook
864 2
        $worksheet->rebindParent($this);
865
866
        // update the cellXfs
867 2
        foreach ($worksheet->getCoordinates(false) as $coordinate) {
868 2
            $cell = $worksheet->getCell($coordinate);
869 2
            $cell->setXfIndex($cell->getXfIndex() + $countCellXfs);
870
        }
871
872 2
        return $this->addSheet($worksheet, $sheetIndex);
873
    }
874
875
    /**
876
     * Get an array of all Named Ranges.
877
     *
878
     * @return DefinedName[]
879
     */
880 8
    public function getNamedRanges(): array
881
    {
882 8
        return array_filter(
883 8
            $this->definedNames,
884 8
            function (DefinedName $definedName) {
885 8
                return $definedName->isFormula() === self::DEFINED_NAME_IS_RANGE;
886 8
            }
887
        );
888
    }
889
890
    /**
891
     * Get an array of all Named Formulae.
892
     *
893
     * @return DefinedName[]
894
     */
895 8
    public function getNamedFormulae(): array
896
    {
897 8
        return array_filter(
898 8
            $this->definedNames,
899 8
            function (DefinedName $definedName) {
900 8
                return $definedName->isFormula() === self::DEFINED_NAME_IS_FORMULA;
901 8
            }
902
        );
903
    }
904
905
    /**
906
     * Get an array of all Defined Names (both named ranges and named formulae).
907
     *
908
     * @return DefinedName[]
909
     */
910 243
    public function getDefinedNames(): array
911
    {
912 243
        return $this->definedNames;
913
    }
914
915
    /**
916
     * Add a named range.
917
     * If a named range with this name already exists, then this will replace the existing value.
918
     */
919 160
    public function addNamedRange(NamedRange $namedRange): void
920
    {
921 160
        $this->addDefinedName($namedRange);
922 160
    }
923
924
    /**
925
     * Add a named formula.
926
     * If a named formula with this name already exists, then this will replace the existing value.
927
     */
928 9
    public function addNamedFormula(NamedFormula $namedFormula): void
929
    {
930 9
        $this->addDefinedName($namedFormula);
931 9
    }
932
933
    /**
934
     * Add a defined name (either a named range or a named formula).
935
     * If a defined named with this name already exists, then this will replace the existing value.
936
     */
937 247
    public function addDefinedName(DefinedName $definedName): void
938
    {
939 247
        $upperCaseName = StringHelper::strToUpper($definedName->getName());
940 247
        if ($definedName->getScope() == null) {
941
            // global scope
942 235
            $this->definedNames[$upperCaseName] = $definedName;
943
        } else {
944
            // local scope
945 111
            $this->definedNames[$definedName->getScope()->getTitle() . '!' . $upperCaseName] = $definedName;
946
        }
947 247
    }
948
949
    /**
950
     * Get named range.
951
     *
952
     * @param null|Worksheet $worksheet Scope. Use null for global scope
953
     */
954 9
    public function getNamedRange(string $namedRange, ?Worksheet $worksheet = null): ?NamedRange
955
    {
956 9
        $returnValue = null;
957
958 9
        if ($namedRange !== '') {
959 9
            $namedRange = StringHelper::strToUpper($namedRange);
960
            // first look for global named range
961 9
            $returnValue = $this->getGlobalDefinedNameByType($namedRange, self::DEFINED_NAME_IS_RANGE);
962
            // then look for local named range (has priority over global named range if both names exist)
963 9
            $returnValue = $this->getLocalDefinedNameByType($namedRange, self::DEFINED_NAME_IS_RANGE, $worksheet) ?: $returnValue;
964
        }
965
966 9
        return $returnValue instanceof NamedRange ? $returnValue : null;
967
    }
968
969
    /**
970
     * Get named formula.
971
     *
972
     * @param null|Worksheet $worksheet Scope. Use null for global scope
973
     */
974 8
    public function getNamedFormula(string $namedFormula, ?Worksheet $worksheet = null): ?NamedFormula
975
    {
976 8
        $returnValue = null;
977
978 8
        if ($namedFormula !== '') {
979 8
            $namedFormula = StringHelper::strToUpper($namedFormula);
980
            // first look for global named formula
981 8
            $returnValue = $this->getGlobalDefinedNameByType($namedFormula, self::DEFINED_NAME_IS_FORMULA);
982
            // then look for local named formula (has priority over global named formula if both names exist)
983 8
            $returnValue = $this->getLocalDefinedNameByType($namedFormula, self::DEFINED_NAME_IS_FORMULA, $worksheet) ?: $returnValue;
984
        }
985
986 8
        return $returnValue instanceof NamedFormula ? $returnValue : null;
987
    }
988
989 17
    private function getGlobalDefinedNameByType(string $name, bool $type): ?DefinedName
990
    {
991 17
        if (isset($this->definedNames[$name]) && $this->definedNames[$name]->isFormula() === $type) {
992 17
            return $this->definedNames[$name];
993
        }
994
995 2
        return null;
996
    }
997
998 17
    private function getLocalDefinedNameByType(string $name, bool $type, ?Worksheet $worksheet = null): ?DefinedName
999
    {
1000
        if (
1001 17
            ($worksheet !== null) && isset($this->definedNames[$worksheet->getTitle() . '!' . $name])
1002 17
            && $this->definedNames[$worksheet->getTitle() . '!' . $name]->isFormula() === $type
1003
        ) {
1004 8
            return $this->definedNames[$worksheet->getTitle() . '!' . $name];
1005
        }
1006
1007 15
        return null;
1008
    }
1009
1010
    /**
1011
     * Get named range.
1012
     *
1013
     * @param null|Worksheet $worksheet Scope. Use null for global scope
1014
     */
1015 4448
    public function getDefinedName(string $definedName, ?Worksheet $worksheet = null): ?DefinedName
1016
    {
1017 4448
        $returnValue = null;
1018
1019 4448
        if ($definedName !== '') {
1020 4448
            $definedName = StringHelper::strToUpper($definedName);
1021
            // first look for global defined name
1022 4448
            if (isset($this->definedNames[$definedName])) {
1023 99
                $returnValue = $this->definedNames[$definedName];
1024
            }
1025
1026
            // then look for local defined name (has priority over global defined name if both names exist)
1027 4448
            if (($worksheet !== null) && isset($this->definedNames[$worksheet->getTitle() . '!' . $definedName])) {
1028 20
                $returnValue = $this->definedNames[$worksheet->getTitle() . '!' . $definedName];
1029
            }
1030
        }
1031
1032 4448
        return $returnValue;
1033
    }
1034
1035
    /**
1036
     * Remove named range.
1037
     *
1038
     * @param null|Worksheet $worksheet scope: use null for global scope
1039
     *
1040
     * @return $this
1041
     */
1042 4
    public function removeNamedRange(string $namedRange, ?Worksheet $worksheet = null): self
1043
    {
1044 4
        if ($this->getNamedRange($namedRange, $worksheet) === null) {
1045
            return $this;
1046
        }
1047
1048 4
        return $this->removeDefinedName($namedRange, $worksheet);
1049
    }
1050
1051
    /**
1052
     * Remove named formula.
1053
     *
1054
     * @param null|Worksheet $worksheet scope: use null for global scope
1055
     *
1056
     * @return $this
1057
     */
1058 3
    public function removeNamedFormula(string $namedFormula, ?Worksheet $worksheet = null): self
1059
    {
1060 3
        if ($this->getNamedFormula($namedFormula, $worksheet) === null) {
1061
            return $this;
1062
        }
1063
1064 3
        return $this->removeDefinedName($namedFormula, $worksheet);
1065
    }
1066
1067
    /**
1068
     * Remove defined name.
1069
     *
1070
     * @param null|Worksheet $worksheet scope: use null for global scope
1071
     *
1072
     * @return $this
1073
     */
1074 10
    public function removeDefinedName(string $definedName, ?Worksheet $worksheet = null): self
1075
    {
1076 10
        $definedName = StringHelper::strToUpper($definedName);
1077
1078 10
        if ($worksheet === null) {
1079
            if (isset($this->definedNames[$definedName])) {
1080
                unset($this->definedNames[$definedName]);
1081
            }
1082
        } else {
1083 10
            if (isset($this->definedNames[$worksheet->getTitle() . '!' . $definedName])) {
1084 3
                unset($this->definedNames[$worksheet->getTitle() . '!' . $definedName]);
1085 7
            } elseif (isset($this->definedNames[$definedName])) {
1086 7
                unset($this->definedNames[$definedName]);
1087
            }
1088
        }
1089
1090 10
        return $this;
1091
    }
1092
1093
    /**
1094
     * Get worksheet iterator.
1095
     *
1096
     * @return Iterator
1097
     */
1098 567
    public function getWorksheetIterator()
1099
    {
1100 567
        return new Iterator($this);
1101
    }
1102
1103
    /**
1104
     * Copy workbook (!= clone!).
1105
     *
1106
     * @return Spreadsheet
1107
     */
1108
    public function copy()
1109
    {
1110
        $copied = clone $this;
1111
1112
        $worksheetCount = count($this->workSheetCollection);
1113
        for ($i = 0; $i < $worksheetCount; ++$i) {
1114
            $this->workSheetCollection[$i] = $this->workSheetCollection[$i]->copy();
1115
            $this->workSheetCollection[$i]->rebindParent($this);
1116
        }
1117
1118
        return $copied;
1119
    }
1120
1121
    /**
1122
     * Implement PHP __clone to create a deep clone, not just a shallow copy.
1123
     */
1124
    public function __clone()
1125
    {
1126
        // @phpstan-ignore-next-line
1127
        foreach ($this as $key => $val) {
1128
            if (is_object($val) || (is_array($val))) {
1129
                $this->{$key} = unserialize(serialize($val));
1130
            }
1131
        }
1132
    }
1133
1134
    /**
1135
     * Get the workbook collection of cellXfs.
1136
     *
1137
     * @return Style[]
1138
     */
1139 409
    public function getCellXfCollection()
1140
    {
1141 409
        return $this->cellXfCollection;
1142
    }
1143
1144
    /**
1145
     * Get cellXf by index.
1146
     *
1147
     * @param int $cellStyleIndex
1148
     *
1149
     * @return Style
1150
     */
1151 4342
    public function getCellXfByIndex($cellStyleIndex)
1152
    {
1153 4342
        return $this->cellXfCollection[$cellStyleIndex];
1154
    }
1155
1156
    /**
1157
     * Get cellXf by hash code.
1158
     *
1159
     * @param string $hashcode
1160
     *
1161
     * @return false|Style
1162
     */
1163 297
    public function getCellXfByHashCode($hashcode)
1164
    {
1165 297
        foreach ($this->cellXfCollection as $cellXf) {
1166 297
            if ($cellXf->getHashCode() === $hashcode) {
1167 130
                return $cellXf;
1168
            }
1169
        }
1170
1171 272
        return false;
1172
    }
1173
1174
    /**
1175
     * Check if style exists in style collection.
1176
     *
1177
     * @param Style $cellStyleIndex
1178
     *
1179
     * @return bool
1180
     */
1181
    public function cellXfExists($cellStyleIndex)
1182
    {
1183
        return in_array($cellStyleIndex, $this->cellXfCollection, true);
1184
    }
1185
1186
    /**
1187
     * Get default style.
1188
     *
1189
     * @return Style
1190
     */
1191 380
    public function getDefaultStyle()
1192
    {
1193 380
        if (isset($this->cellXfCollection[0])) {
1194 380
            return $this->cellXfCollection[0];
1195
        }
1196
1197
        throw new Exception('No default style found for this workbook');
1198
    }
1199
1200
    /**
1201
     * Add a cellXf to the workbook.
1202
     */
1203 4816
    public function addCellXf(Style $style): void
1204
    {
1205 4816
        $this->cellXfCollection[] = $style;
1206 4816
        $style->setIndex(count($this->cellXfCollection) - 1);
1207 4816
    }
1208
1209
    /**
1210
     * Remove cellXf by index. It is ensured that all cells get their xf index updated.
1211
     *
1212
     * @param int $cellStyleIndex Index to cellXf
1213
     */
1214 227
    public function removeCellXfByIndex($cellStyleIndex): void
1215
    {
1216 227
        if ($cellStyleIndex > count($this->cellXfCollection) - 1) {
1217
            throw new Exception('CellXf index is out of bounds.');
1218
        }
1219
1220
        // first remove the cellXf
1221 227
        array_splice($this->cellXfCollection, $cellStyleIndex, 1);
1222
1223
        // then update cellXf indexes for cells
1224 227
        foreach ($this->workSheetCollection as $worksheet) {
1225
            foreach ($worksheet->getCoordinates(false) as $coordinate) {
1226
                $cell = $worksheet->getCell($coordinate);
1227
                $xfIndex = $cell->getXfIndex();
1228
                if ($xfIndex > $cellStyleIndex) {
1229
                    // decrease xf index by 1
1230
                    $cell->setXfIndex($xfIndex - 1);
1231
                } elseif ($xfIndex == $cellStyleIndex) {
1232
                    // set to default xf index 0
1233
                    $cell->setXfIndex(0);
1234
                }
1235
            }
1236
        }
1237 227
    }
1238
1239
    /**
1240
     * Get the cellXf supervisor.
1241
     *
1242
     * @return Style
1243
     */
1244 4286
    public function getCellXfSupervisor()
1245
    {
1246 4286
        return $this->cellXfSupervisor;
1247
    }
1248
1249
    /**
1250
     * Get the workbook collection of cellStyleXfs.
1251
     *
1252
     * @return Style[]
1253
     */
1254 72
    public function getCellStyleXfCollection()
1255
    {
1256 72
        return $this->cellStyleXfCollection;
1257
    }
1258
1259
    /**
1260
     * Get cellStyleXf by index.
1261
     *
1262
     * @param int $cellStyleIndex Index to cellXf
1263
     *
1264
     * @return Style
1265
     */
1266
    public function getCellStyleXfByIndex($cellStyleIndex)
1267
    {
1268
        return $this->cellStyleXfCollection[$cellStyleIndex];
1269
    }
1270
1271
    /**
1272
     * Get cellStyleXf by hash code.
1273
     *
1274
     * @param string $hashcode
1275
     *
1276
     * @return false|Style
1277
     */
1278
    public function getCellStyleXfByHashCode($hashcode)
1279
    {
1280
        foreach ($this->cellStyleXfCollection as $cellStyleXf) {
1281
            if ($cellStyleXf->getHashCode() === $hashcode) {
1282
                return $cellStyleXf;
1283
            }
1284
        }
1285
1286
        return false;
1287
    }
1288
1289
    /**
1290
     * Add a cellStyleXf to the workbook.
1291
     */
1292 4816
    public function addCellStyleXf(Style $style): void
1293
    {
1294 4816
        $this->cellStyleXfCollection[] = $style;
1295 4816
        $style->setIndex(count($this->cellStyleXfCollection) - 1);
1296 4816
    }
1297
1298
    /**
1299
     * Remove cellStyleXf by index.
1300
     *
1301
     * @param int $cellStyleIndex Index to cellXf
1302
     */
1303 227
    public function removeCellStyleXfByIndex($cellStyleIndex): void
1304
    {
1305 227
        if ($cellStyleIndex > count($this->cellStyleXfCollection) - 1) {
1306
            throw new Exception('CellStyleXf index is out of bounds.');
1307
        }
1308 227
        array_splice($this->cellStyleXfCollection, $cellStyleIndex, 1);
1309 227
    }
1310
1311
    /**
1312
     * Eliminate all unneeded cellXf and afterwards update the xfIndex for all cells
1313
     * and columns in the workbook.
1314
     */
1315 385
    public function garbageCollect(): void
1316
    {
1317
        // how many references are there to each cellXf ?
1318 385
        $countReferencesCellXf = [];
1319 385
        foreach ($this->cellXfCollection as $index => $cellXf) {
1320 385
            $countReferencesCellXf[$index] = 0;
1321
        }
1322
1323 385
        foreach ($this->getWorksheetIterator() as $sheet) {
1324
            // from cells
1325 385
            foreach ($sheet->getCoordinates(false) as $coordinate) {
1326 374
                $cell = $sheet->getCell($coordinate);
1327 374
                ++$countReferencesCellXf[$cell->getXfIndex()];
1328
            }
1329
1330
            // from row dimensions
1331 385
            foreach ($sheet->getRowDimensions() as $rowDimension) {
1332 57
                if ($rowDimension->getXfIndex() !== null) {
1333
                    ++$countReferencesCellXf[$rowDimension->getXfIndex()];
1334
                }
1335
            }
1336
1337
            // from column dimensions
1338 385
            foreach ($sheet->getColumnDimensions() as $columnDimension) {
1339 59
                ++$countReferencesCellXf[$columnDimension->getXfIndex()];
1340
            }
1341
        }
1342
1343
        // remove cellXfs without references and create mapping so we can update xfIndex
1344
        // for all cells and columns
1345 385
        $countNeededCellXfs = 0;
1346 385
        $map = [];
1347 385
        foreach ($this->cellXfCollection as $index => $cellXf) {
1348 385
            if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf
1349 385
                ++$countNeededCellXfs;
1350
            } else {
1351 21
                unset($this->cellXfCollection[$index]);
1352
            }
1353 385
            $map[$index] = $countNeededCellXfs - 1;
1354
        }
1355 385
        $this->cellXfCollection = array_values($this->cellXfCollection);
1356
1357
        // update the index for all cellXfs
1358 385
        foreach ($this->cellXfCollection as $i => $cellXf) {
1359 385
            $cellXf->setIndex($i);
1360
        }
1361
1362
        // make sure there is always at least one cellXf (there should be)
1363 385
        if (empty($this->cellXfCollection)) {
1364
            $this->cellXfCollection[] = new Style();
1365
        }
1366
1367
        // update the xfIndex for all cells, row dimensions, column dimensions
1368 385
        foreach ($this->getWorksheetIterator() as $sheet) {
1369
            // for all cells
1370 385
            foreach ($sheet->getCoordinates(false) as $coordinate) {
1371 374
                $cell = $sheet->getCell($coordinate);
1372 374
                $cell->setXfIndex($map[$cell->getXfIndex()]);
1373
            }
1374
1375
            // for all row dimensions
1376 385
            foreach ($sheet->getRowDimensions() as $rowDimension) {
1377 57
                if ($rowDimension->getXfIndex() !== null) {
1378
                    $rowDimension->setXfIndex($map[$rowDimension->getXfIndex()]);
1379
                }
1380
            }
1381
1382
            // for all column dimensions
1383 385
            foreach ($sheet->getColumnDimensions() as $columnDimension) {
1384 59
                $columnDimension->setXfIndex($map[$columnDimension->getXfIndex()]);
1385
            }
1386
1387
            // also do garbage collection for all the sheets
1388 385
            $sheet->garbageCollect();
1389
        }
1390 385
    }
1391
1392
    /**
1393
     * Return the unique ID value assigned to this spreadsheet workbook.
1394
     *
1395
     * @return string
1396
     */
1397
    public function getID()
1398
    {
1399
        return $this->uniqueID;
1400
    }
1401
1402
    /**
1403
     * Get the visibility of the horizonal scroll bar in the application.
1404
     *
1405
     * @return bool True if horizonal scroll bar is visible
1406
     */
1407 159
    public function getShowHorizontalScroll()
1408
    {
1409 159
        return $this->showHorizontalScroll;
1410
    }
1411
1412
    /**
1413
     * Set the visibility of the horizonal scroll bar in the application.
1414
     *
1415
     * @param bool $showHorizontalScroll True if horizonal scroll bar is visible
1416
     */
1417 88
    public function setShowHorizontalScroll($showHorizontalScroll): void
1418
    {
1419 88
        $this->showHorizontalScroll = (bool) $showHorizontalScroll;
1420 88
    }
1421
1422
    /**
1423
     * Get the visibility of the vertical scroll bar in the application.
1424
     *
1425
     * @return bool True if vertical scroll bar is visible
1426
     */
1427 159
    public function getShowVerticalScroll()
1428
    {
1429 159
        return $this->showVerticalScroll;
1430
    }
1431
1432
    /**
1433
     * Set the visibility of the vertical scroll bar in the application.
1434
     *
1435
     * @param bool $showVerticalScroll True if vertical scroll bar is visible
1436
     */
1437 88
    public function setShowVerticalScroll($showVerticalScroll): void
1438
    {
1439 88
        $this->showVerticalScroll = (bool) $showVerticalScroll;
1440 88
    }
1441
1442
    /**
1443
     * Get the visibility of the sheet tabs in the application.
1444
     *
1445
     * @return bool True if the sheet tabs are visible
1446
     */
1447 159
    public function getShowSheetTabs()
1448
    {
1449 159
        return $this->showSheetTabs;
1450
    }
1451
1452
    /**
1453
     * Set the visibility of the sheet tabs  in the application.
1454
     *
1455
     * @param bool $showSheetTabs True if sheet tabs are visible
1456
     */
1457 88
    public function setShowSheetTabs($showSheetTabs): void
1458
    {
1459 88
        $this->showSheetTabs = (bool) $showSheetTabs;
1460 88
    }
1461
1462
    /**
1463
     * Return whether the workbook window is minimized.
1464
     *
1465
     * @return bool true if workbook window is minimized
1466
     */
1467 159
    public function getMinimized()
1468
    {
1469 159
        return $this->minimized;
1470
    }
1471
1472
    /**
1473
     * Set whether the workbook window is minimized.
1474
     *
1475
     * @param bool $minimized true if workbook window is minimized
1476
     */
1477 88
    public function setMinimized($minimized): void
1478
    {
1479 88
        $this->minimized = (bool) $minimized;
1480 88
    }
1481
1482
    /**
1483
     * Return whether to group dates when presenting the user with
1484
     * filtering optiomd in the user interface.
1485
     *
1486
     * @return bool true if workbook window is minimized
1487
     */
1488 159
    public function getAutoFilterDateGrouping()
1489
    {
1490 159
        return $this->autoFilterDateGrouping;
1491
    }
1492
1493
    /**
1494
     * Set whether to group dates when presenting the user with
1495
     * filtering optiomd in the user interface.
1496
     *
1497
     * @param bool $autoFilterDateGrouping true if workbook window is minimized
1498
     */
1499 88
    public function setAutoFilterDateGrouping($autoFilterDateGrouping): void
1500
    {
1501 88
        $this->autoFilterDateGrouping = (bool) $autoFilterDateGrouping;
1502 88
    }
1503
1504
    /**
1505
     * Return the first sheet in the book view.
1506
     *
1507
     * @return int First sheet in book view
1508
     */
1509 159
    public function getFirstSheetIndex()
1510
    {
1511 159
        return $this->firstSheetIndex;
1512
    }
1513
1514
    /**
1515
     * Set the first sheet in the book view.
1516
     *
1517
     * @param int $firstSheetIndex First sheet in book view
1518
     */
1519 88
    public function setFirstSheetIndex($firstSheetIndex): void
1520
    {
1521 88
        if ($firstSheetIndex >= 0) {
1522 88
            $this->firstSheetIndex = (int) $firstSheetIndex;
1523
        } else {
1524
            throw new Exception('First sheet index must be a positive integer.');
1525
        }
1526 88
    }
1527
1528
    /**
1529
     * Return the visibility status of the workbook.
1530
     *
1531
     * This may be one of the following three values:
1532
     * - visibile
1533
     *
1534
     * @return string Visible status
1535
     */
1536 159
    public function getVisibility()
1537
    {
1538 159
        return $this->visibility;
1539
    }
1540
1541
    /**
1542
     * Set the visibility status of the workbook.
1543
     *
1544
     * Valid values are:
1545
     *  - 'visible' (self::VISIBILITY_VISIBLE):
1546
     *       Workbook window is visible
1547
     *  - 'hidden' (self::VISIBILITY_HIDDEN):
1548
     *       Workbook window is hidden, but can be shown by the user
1549
     *       via the user interface
1550
     *  - 'veryHidden' (self::VISIBILITY_VERY_HIDDEN):
1551
     *       Workbook window is hidden and cannot be shown in the
1552
     *       user interface.
1553
     *
1554
     * @param string $visibility visibility status of the workbook
1555
     */
1556 88
    public function setVisibility($visibility): void
1557
    {
1558 88
        if ($visibility === null) {
0 ignored issues
show
introduced by
The condition $visibility === null is always false.
Loading history...
1559
            $visibility = self::VISIBILITY_VISIBLE;
1560
        }
1561
1562 88
        if (in_array($visibility, self::$workbookViewVisibilityValues)) {
1563 88
            $this->visibility = $visibility;
1564
        } else {
1565
            throw new Exception('Invalid visibility value.');
1566
        }
1567 88
    }
1568
1569
    /**
1570
     * Get the ratio between the workbook tabs bar and the horizontal scroll bar.
1571
     * TabRatio is assumed to be out of 1000 of the horizontal window width.
1572
     *
1573
     * @return int Ratio between the workbook tabs bar and the horizontal scroll bar
1574
     */
1575 159
    public function getTabRatio()
1576
    {
1577 159
        return $this->tabRatio;
1578
    }
1579
1580
    /**
1581
     * Set the ratio between the workbook tabs bar and the horizontal scroll bar
1582
     * TabRatio is assumed to be out of 1000 of the horizontal window width.
1583
     *
1584
     * @param int $tabRatio Ratio between the tabs bar and the horizontal scroll bar
1585
     */
1586 89
    public function setTabRatio($tabRatio): void
1587
    {
1588 89
        if ($tabRatio >= 0 || $tabRatio <= 1000) {
1589 89
            $this->tabRatio = (int) $tabRatio;
1590
        } else {
1591
            throw new Exception('Tab ratio must be between 0 and 1000.');
1592
        }
1593 89
    }
1594
}
1595