Failed Conditions
Push — master ( a2bb82...a189d9 )
by Adrien
10:27 queued 01:00
created

Spreadsheet::garbageCollect()   F

Complexity

Conditions 17
Paths 4056

Size

Total Lines 74
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 17.1819

Importance

Changes 0
Metric Value
cc 17
eloc 35
c 0
b 0
f 0
nc 4056
nop 0
dl 0
loc 74
ccs 32
cts 35
cp 0.9143
crap 17.1819
rs 1.0499

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet;
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 NamedRange[]
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 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 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|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 128
    public function hasMacros()
208
    {
209 128
        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];
0 ignored issues
show
Documentation Bug introduced by
It seems like array('target' => $target, 'data' => $xmlData) of type array<string,mixed> is incompatible with the declared type null|string of property $ribbonXMLData.

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...
293
        } else {
294
            $this->ribbonXMLData = null;
295
        }
296
    }
297
298
    /**
299
     * retrieve ribbon XML Data.
300
     *
301
     * return string|null|array
302
     *
303
     * @param string $what
304
     *
305
     * @return string
306
     */
307
    public function getRibbonXMLData($what = 'all') //we need some constants here...
308
    {
309
        $returnData = null;
310
        $what = strtolower($what);
311
        switch ($what) {
312
            case 'all':
313
                $returnData = $this->ribbonXMLData;
314
315
                break;
316
            case 'target':
317
            case 'data':
318
                if (is_array($this->ribbonXMLData) && isset($this->ribbonXMLData[$what])) {
0 ignored issues
show
introduced by
The condition is_array($this->ribbonXMLData) is always false.
Loading history...
319
                    $returnData = $this->ribbonXMLData[$what];
320
                }
321
322
                break;
323
        }
324
325
        return $returnData;
326
    }
327
328
    /**
329
     * store binaries ribbon objects (pictures).
330
     *
331
     * @param null|mixed $BinObjectsNames
332
     * @param null|mixed $BinObjectsData
333
     */
334
    public function setRibbonBinObjects($BinObjectsNames, $BinObjectsData): void
335
    {
336
        if ($BinObjectsNames !== null && $BinObjectsData !== null) {
337
            $this->ribbonBinObjects = ['names' => $BinObjectsNames, 'data' => $BinObjectsData];
338
        } else {
339
            $this->ribbonBinObjects = null;
340
        }
341
    }
342
343
    /**
344
     * List of unparsed loaded data for export to same format with better compatibility.
345
     * It has to be minimized when the library start to support currently unparsed data.
346
     *
347
     * @internal
348
     *
349
     * @return array
350
     */
351 128
    public function getUnparsedLoadedData()
352
    {
353 128
        return $this->unparsedLoadedData;
354
    }
355
356
    /**
357
     * List of unparsed loaded data for export to same format with better compatibility.
358
     * It has to be minimized when the library start to support currently unparsed data.
359
     *
360
     * @internal
361
     */
362 123
    public function setUnparsedLoadedData(array $unparsedLoadedData): void
363
    {
364 123
        $this->unparsedLoadedData = $unparsedLoadedData;
365 123
    }
366
367
    /**
368
     * return the extension of a filename. Internal use for a array_map callback (php<5.3 don't like lambda function).
369
     *
370
     * @param mixed $path
371
     *
372
     * @return string
373
     */
374
    private function getExtensionOnly($path)
375
    {
376
        $extension = pathinfo($path, PATHINFO_EXTENSION);
377
378
        return is_array($extension) ? '' : $extension;
379
    }
380
381
    /**
382
     * retrieve Binaries Ribbon Objects.
383
     *
384
     * @param string $what
385
     *
386
     * @return null|array
387
     */
388
    public function getRibbonBinObjects($what = 'all')
389
    {
390
        $ReturnData = null;
391
        $what = strtolower($what);
392
        switch ($what) {
393
            case 'all':
394
                return $this->ribbonBinObjects;
395
396
                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...
397
            case 'names':
398
            case 'data':
399
                if (is_array($this->ribbonBinObjects) && isset($this->ribbonBinObjects[$what])) {
400
                    $ReturnData = $this->ribbonBinObjects[$what];
401
                }
402
403
                break;
404
            case 'types':
405
                if (
406
                    is_array($this->ribbonBinObjects) &&
407
                    isset($this->ribbonBinObjects['data']) && is_array($this->ribbonBinObjects['data'])
408
                ) {
409
                    $tmpTypes = array_keys($this->ribbonBinObjects['data']);
410
                    $ReturnData = array_unique(array_map([$this, 'getExtensionOnly'], $tmpTypes));
411
                } else {
412
                    $ReturnData = []; // the caller want an array... not null if empty
413
                }
414
415
                break;
416
        }
417
418
        return $ReturnData;
419
    }
420
421
    /**
422
     * This workbook have a custom UI ?
423
     *
424
     * @return bool
425
     */
426 128
    public function hasRibbon()
427
    {
428 128
        return $this->ribbonXMLData !== null;
429
    }
430
431
    /**
432
     * This workbook have additionnal object for the ribbon ?
433
     *
434
     * @return bool
435
     */
436 128
    public function hasRibbonBinObjects()
437
    {
438 128
        return $this->ribbonBinObjects !== null;
439
    }
440
441
    /**
442
     * Check if a sheet with a specified code name already exists.
443
     *
444
     * @param string $pSheetCodeName Name of the worksheet to check
445
     *
446
     * @return bool
447
     */
448 3865
    public function sheetCodeNameExists($pSheetCodeName)
449
    {
450 3865
        return $this->getSheetByCodeName($pSheetCodeName) !== null;
451
    }
452
453
    /**
454
     * Get sheet by code name. Warning : sheet don't have always a code name !
455
     *
456
     * @param string $pName Sheet name
457
     *
458
     * @return Worksheet
459
     */
460 3865
    public function getSheetByCodeName($pName)
461
    {
462 3865
        $worksheetCount = count($this->workSheetCollection);
463 3865
        for ($i = 0; $i < $worksheetCount; ++$i) {
464 139
            if ($this->workSheetCollection[$i]->getCodeName() == $pName) {
465 92
                return $this->workSheetCollection[$i];
466
            }
467
        }
468
469 3865
        return null;
470
    }
471
472
    /**
473
     * Create a new PhpSpreadsheet with one Worksheet.
474
     */
475 3865
    public function __construct()
476
    {
477 3865
        $this->uniqueID = uniqid('', true);
478 3865
        $this->calculationEngine = new Calculation($this);
479
480
        // Initialise worksheet collection and add one worksheet
481 3865
        $this->workSheetCollection = [];
482 3865
        $this->workSheetCollection[] = new Worksheet($this);
483 3865
        $this->activeSheetIndex = 0;
484
485
        // Create document properties
486 3865
        $this->properties = new Document\Properties();
487
488
        // Create document security
489 3865
        $this->security = new Document\Security();
490
491
        // Set defined names
492 3865
        $this->definedNames = [];
493
494
        // Create the cellXf supervisor
495 3865
        $this->cellXfSupervisor = new Style(true);
496 3865
        $this->cellXfSupervisor->bindParent($this);
497
498
        // Create the default style
499 3865
        $this->addCellXf(new Style());
500 3865
        $this->addCellStyleXf(new Style());
501 3865
    }
502
503
    /**
504
     * Code to execute when this worksheet is unset().
505
     */
506 30
    public function __destruct()
507
    {
508 30
        $this->disconnectWorksheets();
509 30
        $this->calculationEngine = null;
510 30
    }
511
512
    /**
513
     * Disconnect all worksheets from this PhpSpreadsheet workbook object,
514
     * typically so that the PhpSpreadsheet object can be unset.
515
     */
516 2290
    public function disconnectWorksheets(): void
517
    {
518 2290
        $worksheet = null;
519 2290
        foreach ($this->workSheetCollection as $k => &$worksheet) {
520 2290
            $worksheet->disconnectCells();
521 2290
            $this->workSheetCollection[$k] = null;
522
        }
523 2290
        unset($worksheet);
524 2290
        $this->workSheetCollection = [];
525 2290
    }
526
527
    /**
528
     * Return the calculation engine for this worksheet.
529
     *
530
     * @return null|Calculation
531
     */
532 3865
    public function getCalculationEngine()
533
    {
534 3865
        return $this->calculationEngine;
535
    }
536
537
    /**
538
     * Get properties.
539
     *
540
     * @return Document\Properties
541
     */
542 424
    public function getProperties()
543
    {
544 424
        return $this->properties;
545
    }
546
547
    /**
548
     * Set properties.
549
     */
550
    public function setProperties(Document\Properties $pValue): void
551
    {
552
        $this->properties = $pValue;
553
    }
554
555
    /**
556
     * Get security.
557
     *
558
     * @return Document\Security
559
     */
560 128
    public function getSecurity()
561
    {
562 128
        return $this->security;
563
    }
564
565
    /**
566
     * Set security.
567
     */
568
    public function setSecurity(Document\Security $pValue): void
569
    {
570
        $this->security = $pValue;
571
    }
572
573
    /**
574
     * Get active sheet.
575
     *
576
     * @return Worksheet
577
     */
578 3831
    public function getActiveSheet()
579
    {
580 3831
        return $this->getSheet($this->activeSheetIndex);
581
    }
582
583
    /**
584
     * Create sheet and add it to this workbook.
585
     *
586
     * @param null|int $sheetIndex Index where sheet should go (0,1,..., or null for last)
587
     *
588
     * @return Worksheet
589
     */
590 255
    public function createSheet($sheetIndex = null)
591
    {
592 255
        $newSheet = new Worksheet($this);
593 255
        $this->addSheet($newSheet, $sheetIndex);
594
595 255
        return $newSheet;
596
    }
597
598
    /**
599
     * Check if a sheet with a specified name already exists.
600
     *
601
     * @param string $pSheetName Name of the worksheet to check
602
     *
603
     * @return bool
604
     */
605 3865
    public function sheetNameExists($pSheetName)
606
    {
607 3865
        return $this->getSheetByName($pSheetName) !== null;
608
    }
609
610
    /**
611
     * Add sheet.
612
     *
613
     * @param null|int $iSheetIndex Index where sheet should go (0,1,..., or null for last)
614
     *
615
     * @return Worksheet
616
     */
617 301
    public function addSheet(Worksheet $pSheet, $iSheetIndex = null)
618
    {
619 301
        if ($this->sheetNameExists($pSheet->getTitle())) {
620 1
            throw new Exception(
621 1
                "Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename this worksheet first."
622
            );
623
        }
624
625 301
        if ($iSheetIndex === null) {
626 299
            if ($this->activeSheetIndex < 0) {
627 184
                $this->activeSheetIndex = 0;
628
            }
629 299
            $this->workSheetCollection[] = $pSheet;
630
        } else {
631
            // Insert the sheet at the requested index
632 5
            array_splice(
633 5
                $this->workSheetCollection,
634
                $iSheetIndex,
635 5
                0,
636 5
                [$pSheet]
637
            );
638
639
            // Adjust active sheet index if necessary
640 5
            if ($this->activeSheetIndex >= $iSheetIndex) {
641 1
                ++$this->activeSheetIndex;
642
            }
643
        }
644
645 301
        if ($pSheet->getParent() === null) {
646 45
            $pSheet->rebindParent($this);
647
        }
648
649 301
        return $pSheet;
650
    }
651
652
    /**
653
     * Remove sheet by index.
654
     *
655
     * @param int $pIndex Active sheet index
656
     */
657 191
    public function removeSheetByIndex($pIndex): void
658
    {
659 191
        $numSheets = count($this->workSheetCollection);
660 191
        if ($pIndex > $numSheets - 1) {
661 1
            throw new Exception(
662 1
                "You tried to remove a sheet by the out of bounds index: {$pIndex}. The actual number of sheets is {$numSheets}."
663
            );
664
        }
665 190
        array_splice($this->workSheetCollection, $pIndex, 1);
666
667
        // Adjust active sheet index if necessary
668
        if (
669 190
            ($this->activeSheetIndex >= $pIndex) &&
670 190
            ($this->activeSheetIndex > 0 || $numSheets <= 1)
671
        ) {
672 188
            --$this->activeSheetIndex;
673
        }
674 190
    }
675
676
    /**
677
     * Get sheet by index.
678
     *
679
     * @param int $pIndex Sheet index
680
     *
681
     * @return Worksheet
682
     */
683 3847
    public function getSheet($pIndex)
684
    {
685 3847
        if (!isset($this->workSheetCollection[$pIndex])) {
686 1
            $numSheets = $this->getSheetCount();
687
688 1
            throw new Exception(
689 1
                "Your requested sheet index: {$pIndex} is out of bounds. The actual number of sheets is {$numSheets}."
690
            );
691
        }
692
693 3847
        return $this->workSheetCollection[$pIndex];
694
    }
695
696
    /**
697
     * Get all sheets.
698
     *
699
     * @return Worksheet[]
700
     */
701 75
    public function getAllSheets()
702
    {
703 75
        return $this->workSheetCollection;
704
    }
705
706
    /**
707
     * Get sheet by name.
708
     *
709
     * @param string $pName Sheet name
710
     *
711
     * @return null|Worksheet
712
     */
713 3865
    public function getSheetByName($pName)
714
    {
715 3865
        $worksheetCount = count($this->workSheetCollection);
716 3865
        for ($i = 0; $i < $worksheetCount; ++$i) {
717 3532
            if ($this->workSheetCollection[$i]->getTitle() === trim($pName, "'")) {
718 3351
                return $this->workSheetCollection[$i];
719
            }
720
        }
721
722 3865
        return null;
723
    }
724
725
    /**
726
     * Get index for sheet.
727
     *
728
     * @return int index
729
     */
730 3617
    public function getIndex(Worksheet $pSheet)
731
    {
732 3617
        foreach ($this->workSheetCollection as $key => $value) {
733 3617
            if ($value->getHashCode() === $pSheet->getHashCode()) {
734 3616
                return $key;
735
            }
736
        }
737
738 1
        throw new Exception('Sheet does not exist.');
739
    }
740
741
    /**
742
     * Set index for sheet by sheet name.
743
     *
744
     * @param string $sheetName Sheet name to modify index for
745
     * @param int $newIndex New index for the sheet
746
     *
747
     * @return int New sheet index
748
     */
749 1
    public function setIndexByName($sheetName, $newIndex)
750
    {
751 1
        $oldIndex = $this->getIndex($this->getSheetByName($sheetName));
1 ignored issue
show
Bug introduced by
It seems like $this->getSheetByName($sheetName) can also be of type null; however, parameter $pSheet 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

751
        $oldIndex = $this->getIndex(/** @scrutinizer ignore-type */ $this->getSheetByName($sheetName));
Loading history...
752 1
        $pSheet = array_splice(
753 1
            $this->workSheetCollection,
754
            $oldIndex,
755 1
            1
756
        );
757 1
        array_splice(
758 1
            $this->workSheetCollection,
759
            $newIndex,
760 1
            0,
761
            $pSheet
762
        );
763
764 1
        return $newIndex;
765
    }
766
767
    /**
768
     * Get sheet count.
769
     *
770
     * @return int
771
     */
772 482
    public function getSheetCount()
773
    {
774 482
        return count($this->workSheetCollection);
775
    }
776
777
    /**
778
     * Get active sheet index.
779
     *
780
     * @return int Active sheet index
781
     */
782 3362
    public function getActiveSheetIndex()
783
    {
784 3362
        return $this->activeSheetIndex;
785
    }
786
787
    /**
788
     * Set active sheet index.
789
     *
790
     * @param int $pIndex Active sheet index
791
     *
792
     * @return Worksheet
793
     */
794 3696
    public function setActiveSheetIndex($pIndex)
795
    {
796 3696
        $numSheets = count($this->workSheetCollection);
797
798 3696
        if ($pIndex > $numSheets - 1) {
799 1
            throw new Exception(
800 1
                "You tried to set a sheet active by the out of bounds index: {$pIndex}. The actual number of sheets is {$numSheets}."
801
            );
802
        }
803 3695
        $this->activeSheetIndex = $pIndex;
804
805 3695
        return $this->getActiveSheet();
806
    }
807
808
    /**
809
     * Set active sheet index by name.
810
     *
811
     * @param string $pValue Sheet title
812
     *
813
     * @return Worksheet
814
     */
815 27
    public function setActiveSheetIndexByName($pValue)
816
    {
817 27
        if (($worksheet = $this->getSheetByName($pValue)) instanceof Worksheet) {
818 25
            $this->setActiveSheetIndex($this->getIndex($worksheet));
819
820 25
            return $worksheet;
821
        }
822
823 2
        throw new Exception('Workbook does not contain sheet:' . $pValue);
824
    }
825
826
    /**
827
     * Get sheet names.
828
     *
829
     * @return string[]
830
     */
831 9
    public function getSheetNames()
832
    {
833 9
        $returnValue = [];
834 9
        $worksheetCount = $this->getSheetCount();
835 9
        for ($i = 0; $i < $worksheetCount; ++$i) {
836 9
            $returnValue[] = $this->getSheet($i)->getTitle();
837
        }
838
839 9
        return $returnValue;
840
    }
841
842
    /**
843
     * Add external sheet.
844
     *
845
     * @param Worksheet $pSheet External sheet to add
846
     * @param null|int $iSheetIndex Index where sheet should go (0,1,..., or null for last)
847
     *
848
     * @return Worksheet
849
     */
850 3
    public function addExternalSheet(Worksheet $pSheet, $iSheetIndex = null)
851
    {
852 3
        if ($this->sheetNameExists($pSheet->getTitle())) {
853 1
            throw new Exception("Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename the external sheet first.");
854
        }
855
856
        // count how many cellXfs there are in this workbook currently, we will need this below
857 2
        $countCellXfs = count($this->cellXfCollection);
858
859
        // copy all the shared cellXfs from the external workbook and append them to the current
860 2
        foreach ($pSheet->getParent()->getCellXfCollection() as $cellXf) {
861 2
            $this->addCellXf(clone $cellXf);
862
        }
863
864
        // move sheet to this workbook
865 2
        $pSheet->rebindParent($this);
866
867
        // update the cellXfs
868 2
        foreach ($pSheet->getCoordinates(false) as $coordinate) {
869 2
            $cell = $pSheet->getCell($coordinate);
870 2
            $cell->setXfIndex($cell->getXfIndex() + $countCellXfs);
871
        }
872
873 2
        return $this->addSheet($pSheet, $iSheetIndex);
874
    }
875
876
    /**
877
     * Get an array of all Named Ranges.
878
     *
879
     * @return NamedRange[]
880
     */
881 8
    public function getNamedRanges(): array
882
    {
883 8
        return array_filter(
884 8
            $this->definedNames,
885
            function (DefinedName $definedName) {
886 8
                return $definedName->isFormula() === self::DEFINED_NAME_IS_RANGE;
887 8
            }
888
        );
889
    }
890
891
    /**
892
     * Get an array of all Named Formulae.
893
     *
894
     * @return NamedFormula[]
895
     */
896 8
    public function getNamedFormulae(): array
897
    {
898 8
        return array_filter(
899 8
            $this->definedNames,
900
            function (DefinedName $definedName) {
901 8
                return $definedName->isFormula() === self::DEFINED_NAME_IS_FORMULA;
902 8
            }
903
        );
904
    }
905
906
    /**
907
     * Get an array of all Defined Names (both named ranges and named formulae).
908
     *
909
     * @return DefinedName[]
910
     */
911 185
    public function getDefinedNames(): array
912
    {
913 185
        return $this->definedNames;
914
    }
915
916
    /**
917
     * Add a named range.
918
     * If a named range with this name already exists, then this will replace the existing value.
919
     */
920 55
    public function addNamedRange(NamedRange $namedRange): void
921
    {
922 55
        $this->addDefinedName($namedRange);
923 55
    }
924
925
    /**
926
     * Add a named formula.
927
     * If a named formula with this name already exists, then this will replace the existing value.
928
     */
929 9
    public function addNamedFormula(NamedFormula $namedFormula): void
930
    {
931 9
        $this->addDefinedName($namedFormula);
932 9
    }
933
934
    /**
935
     * Add a defined name (either a named range or a named formula).
936
     * If a defined named with this name already exists, then this will replace the existing value.
937
     */
938 133
    public function addDefinedName(DefinedName $definedName): void
939
    {
940 133
        $upperCaseName = StringHelper::strToUpper($definedName->getName());
941 133
        if ($definedName->getScope() == null) {
942
            // global scope
943 128
            $this->definedNames[$upperCaseName] = $definedName;
944
        } else {
945
            // local scope
946 30
            $this->definedNames[$definedName->getScope()->getTitle() . '!' . $upperCaseName] = $definedName;
947
        }
948 133
    }
949
950
    /**
951
     * Get named range.
952
     *
953
     * @param null|Worksheet $pSheet Scope. Use null for global scope
954
     */
955 9
    public function getNamedRange(string $namedRange, ?Worksheet $pSheet = null): ?NamedRange
956
    {
957 9
        $returnValue = null;
958
959 9
        if ($namedRange !== '') {
960 9
            $namedRange = StringHelper::strToUpper($namedRange);
961
            // first look for global named range
962 9
            $returnValue = $this->getGlobalDefinedNameByType($namedRange, self::DEFINED_NAME_IS_RANGE);
963
            // then look for local named range (has priority over global named range if both names exist)
964 9
            $returnValue = $this->getLocalDefinedNameByType($namedRange, self::DEFINED_NAME_IS_RANGE, $pSheet) ?: $returnValue;
965
        }
966
967 9
        return $returnValue instanceof NamedRange ? $returnValue : null;
968
    }
969
970
    /**
971
     * Get named formula.
972
     *
973
     * @param null|Worksheet $pSheet Scope. Use null for global scope
974
     */
975 7
    public function getNamedFormula(string $namedFormula, ?Worksheet $pSheet = null): ?NamedFormula
976
    {
977 7
        $returnValue = null;
978
979 7
        if ($namedFormula !== '') {
980 7
            $namedFormula = StringHelper::strToUpper($namedFormula);
981
            // first look for global named formula
982 7
            $returnValue = $this->getGlobalDefinedNameByType($namedFormula, self::DEFINED_NAME_IS_FORMULA);
983
            // then look for local named formula (has priority over global named formula if both names exist)
984 7
            $returnValue = $this->getLocalDefinedNameByType($namedFormula, self::DEFINED_NAME_IS_FORMULA, $pSheet) ?: $returnValue;
985
        }
986
987 7
        return $returnValue instanceof NamedFormula ? $returnValue : null;
988
    }
989
990 16
    private function getGlobalDefinedNameByType(string $name, bool $type): ?DefinedName
991
    {
992 16
        if (isset($this->definedNames[$name]) && $this->definedNames[$name]->isFormula() === $type) {
993 16
            return $this->definedNames[$name];
994
        }
995
996 2
        return null;
997
    }
998
999 16
    private function getLocalDefinedNameByType(string $name, bool $type, ?Worksheet $pSheet = null): ?DefinedName
1000
    {
1001
        if (
1002 16
            ($pSheet !== null) && isset($this->definedNames[$pSheet->getTitle() . '!' . $name])
1003 16
            && $this->definedNames[$pSheet->getTitle() . '!' . $name]->isFormula() === $type
1004
        ) {
1005 8
            return $this->definedNames[$pSheet->getTitle() . '!' . $name];
1006
        }
1007
1008 14
        return null;
1009
    }
1010
1011
    /**
1012
     * Get named range.
1013
     *
1014
     * @param null|Worksheet $pSheet Scope. Use null for global scope
1015
     */
1016 97
    public function getDefinedName(string $definedName, ?Worksheet $pSheet = null): ?DefinedName
1017
    {
1018 97
        $returnValue = null;
1019
1020 97
        if ($definedName !== '') {
1021 97
            $definedName = StringHelper::strToUpper($definedName);
1022
            // first look for global defined name
1023 97
            if (isset($this->definedNames[$definedName])) {
1024 68
                $returnValue = $this->definedNames[$definedName];
1025
            }
1026
1027
            // then look for local defined name (has priority over global defined name if both names exist)
1028 97
            if (($pSheet !== null) && isset($this->definedNames[$pSheet->getTitle() . '!' . $definedName])) {
1029 7
                $returnValue = $this->definedNames[$pSheet->getTitle() . '!' . $definedName];
1030
            }
1031
        }
1032
1033 97
        return $returnValue;
1034
    }
1035
1036
    /**
1037
     * Remove named range.
1038
     *
1039
     * @param null|Worksheet $pSheet scope: use null for global scope
1040
     *
1041
     * @return $this
1042
     */
1043 4
    public function removeNamedRange(string $namedRange, ?Worksheet $pSheet = null): self
1044
    {
1045 4
        if ($this->getNamedRange($namedRange, $pSheet) === null) {
1046
            return $this;
1047
        }
1048
1049 4
        return $this->removeDefinedName($namedRange, $pSheet);
1050
    }
1051
1052
    /**
1053
     * Remove named formula.
1054
     *
1055
     * @param null|Worksheet $pSheet scope: use null for global scope
1056
     *
1057
     * @return $this
1058
     */
1059 3
    public function removeNamedFormula(string $namedFormula, ?Worksheet $pSheet = null): self
1060
    {
1061 3
        if ($this->getNamedFormula($namedFormula, $pSheet) === null) {
1062
            return $this;
1063
        }
1064
1065 3
        return $this->removeDefinedName($namedFormula, $pSheet);
1066
    }
1067
1068
    /**
1069
     * Remove defined name.
1070
     *
1071
     * @param null|Worksheet $pSheet scope: use null for global scope
1072
     *
1073
     * @return $this
1074
     */
1075 10
    public function removeDefinedName(string $definedName, ?Worksheet $pSheet = null): self
1076
    {
1077 10
        $definedName = StringHelper::strToUpper($definedName);
1078
1079 10
        if ($pSheet === null) {
1080
            if (isset($this->definedNames[$definedName])) {
1081
                unset($this->definedNames[$definedName]);
1082
            }
1083
        } else {
1084 10
            if (isset($this->definedNames[$pSheet->getTitle() . '!' . $definedName])) {
1085 3
                unset($this->definedNames[$pSheet->getTitle() . '!' . $definedName]);
1086 7
            } elseif (isset($this->definedNames[$definedName])) {
1087 7
                unset($this->definedNames[$definedName]);
1088
            }
1089
        }
1090
1091 10
        return $this;
1092
    }
1093
1094
    /**
1095
     * Get worksheet iterator.
1096
     *
1097
     * @return Iterator
1098
     */
1099 391
    public function getWorksheetIterator()
1100
    {
1101 391
        return new Iterator($this);
1102
    }
1103
1104
    /**
1105
     * Copy workbook (!= clone!).
1106
     *
1107
     * @return Spreadsheet
1108
     */
1109
    public function copy()
1110
    {
1111
        $copied = clone $this;
1112
1113
        $worksheetCount = count($this->workSheetCollection);
1114
        for ($i = 0; $i < $worksheetCount; ++$i) {
1115
            $this->workSheetCollection[$i] = $this->workSheetCollection[$i]->copy();
1116
            $this->workSheetCollection[$i]->rebindParent($this);
1117
        }
1118
1119
        return $copied;
1120
    }
1121
1122
    /**
1123
     * Implement PHP __clone to create a deep clone, not just a shallow copy.
1124
     */
1125
    public function __clone()
1126
    {
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 333
    public function getCellXfCollection()
1140
    {
1141 333
        return $this->cellXfCollection;
1142
    }
1143
1144
    /**
1145
     * Get cellXf by index.
1146
     *
1147
     * @param int $pIndex
1148
     *
1149
     * @return Style
1150
     */
1151 3550
    public function getCellXfByIndex($pIndex)
1152
    {
1153 3550
        return $this->cellXfCollection[$pIndex];
1154
    }
1155
1156
    /**
1157
     * Get cellXf by hash code.
1158
     *
1159
     * @param string $pValue
1160
     *
1161
     * @return false|Style
1162
     */
1163 249
    public function getCellXfByHashCode($pValue)
1164
    {
1165 249
        foreach ($this->cellXfCollection as $cellXf) {
1166 249
            if ($cellXf->getHashCode() === $pValue) {
1167 102
                return $cellXf;
1168
            }
1169
        }
1170
1171 234
        return false;
1172
    }
1173
1174
    /**
1175
     * Check if style exists in style collection.
1176
     *
1177
     * @param Style $pCellStyle
1178
     *
1179
     * @return bool
1180
     */
1181
    public function cellXfExists($pCellStyle)
1182
    {
1183
        return in_array($pCellStyle, $this->cellXfCollection, true);
1184
    }
1185
1186
    /**
1187
     * Get default style.
1188
     *
1189
     * @return Style
1190
     */
1191 320
    public function getDefaultStyle()
1192
    {
1193 320
        if (isset($this->cellXfCollection[0])) {
1194 320
            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 3865
    public function addCellXf(Style $style): void
1204
    {
1205 3865
        $this->cellXfCollection[] = $style;
1206 3865
        $style->setIndex(count($this->cellXfCollection) - 1);
1207 3865
    }
1208
1209
    /**
1210
     * Remove cellXf by index. It is ensured that all cells get their xf index updated.
1211
     *
1212
     * @param int $pIndex Index to cellXf
1213
     */
1214 159
    public function removeCellXfByIndex($pIndex): void
1215
    {
1216 159
        if ($pIndex > count($this->cellXfCollection) - 1) {
1217
            throw new Exception('CellXf index is out of bounds.');
1218
        }
1219
1220
        // first remove the cellXf
1221 159
        array_splice($this->cellXfCollection, $pIndex, 1);
1222
1223
        // then update cellXf indexes for cells
1224 159
        foreach ($this->workSheetCollection as $worksheet) {
1225
            foreach ($worksheet->getCoordinates(false) as $coordinate) {
1226
                $cell = $worksheet->getCell($coordinate);
1227
                $xfIndex = $cell->getXfIndex();
1228
                if ($xfIndex > $pIndex) {
1229
                    // decrease xf index by 1
1230
                    $cell->setXfIndex($xfIndex - 1);
1231
                } elseif ($xfIndex == $pIndex) {
1232
                    // set to default xf index 0
1233
                    $cell->setXfIndex(0);
1234
                }
1235
            }
1236
        }
1237 159
    }
1238
1239
    /**
1240
     * Get the cellXf supervisor.
1241
     *
1242
     * @return Style
1243
     */
1244 3497
    public function getCellXfSupervisor()
1245
    {
1246 3497
        return $this->cellXfSupervisor;
1247
    }
1248
1249
    /**
1250
     * Get the workbook collection of cellStyleXfs.
1251
     *
1252
     * @return Style[]
1253
     */
1254 55
    public function getCellStyleXfCollection()
1255
    {
1256 55
        return $this->cellStyleXfCollection;
1257
    }
1258
1259
    /**
1260
     * Get cellStyleXf by index.
1261
     *
1262
     * @param int $pIndex Index to cellXf
1263
     *
1264
     * @return Style
1265
     */
1266
    public function getCellStyleXfByIndex($pIndex)
1267
    {
1268
        return $this->cellStyleXfCollection[$pIndex];
1269
    }
1270
1271
    /**
1272
     * Get cellStyleXf by hash code.
1273
     *
1274
     * @param string $pValue
1275
     *
1276
     * @return false|Style
1277
     */
1278
    public function getCellStyleXfByHashCode($pValue)
1279
    {
1280
        foreach ($this->cellStyleXfCollection as $cellStyleXf) {
1281
            if ($cellStyleXf->getHashCode() === $pValue) {
1282
                return $cellStyleXf;
1283
            }
1284
        }
1285
1286
        return false;
1287
    }
1288
1289
    /**
1290
     * Add a cellStyleXf to the workbook.
1291
     */
1292 3865
    public function addCellStyleXf(Style $pStyle): void
1293
    {
1294 3865
        $this->cellStyleXfCollection[] = $pStyle;
1295 3865
        $pStyle->setIndex(count($this->cellStyleXfCollection) - 1);
1296 3865
    }
1297
1298
    /**
1299
     * Remove cellStyleXf by index.
1300
     *
1301
     * @param int $pIndex Index to cellXf
1302
     */
1303 159
    public function removeCellStyleXfByIndex($pIndex): void
1304
    {
1305 159
        if ($pIndex > count($this->cellStyleXfCollection) - 1) {
1306
            throw new Exception('CellStyleXf index is out of bounds.');
1307
        }
1308 159
        array_splice($this->cellStyleXfCollection, $pIndex, 1);
1309 159
    }
1310
1311
    /**
1312
     * Eliminate all unneeded cellXf and afterwards update the xfIndex for all cells
1313
     * and columns in the workbook.
1314
     */
1315 313
    public function garbageCollect(): void
1316
    {
1317
        // how many references are there to each cellXf ?
1318 313
        $countReferencesCellXf = [];
1319 313
        foreach ($this->cellXfCollection as $index => $cellXf) {
1320 313
            $countReferencesCellXf[$index] = 0;
1321
        }
1322
1323 313
        foreach ($this->getWorksheetIterator() as $sheet) {
1324
            // from cells
1325 313
            foreach ($sheet->getCoordinates(false) as $coordinate) {
1326 303
                $cell = $sheet->getCell($coordinate);
1327 303
                ++$countReferencesCellXf[$cell->getXfIndex()];
1328
            }
1329
1330
            // from row dimensions
1331 313
            foreach ($sheet->getRowDimensions() as $rowDimension) {
1332 52
                if ($rowDimension->getXfIndex() !== null) {
1333
                    ++$countReferencesCellXf[$rowDimension->getXfIndex()];
1334
                }
1335
            }
1336
1337
            // from column dimensions
1338 313
            foreach ($sheet->getColumnDimensions() as $columnDimension) {
1339 42
                ++$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 313
        $countNeededCellXfs = 0;
1346 313
        $map = [];
1347 313
        foreach ($this->cellXfCollection as $index => $cellXf) {
1348 313
            if ($countReferencesCellXf[$index] > 0 || $index == 0) { // we must never remove the first cellXf
1349 313
                ++$countNeededCellXfs;
1350
            } else {
1351 20
                unset($this->cellXfCollection[$index]);
1352
            }
1353 313
            $map[$index] = $countNeededCellXfs - 1;
1354
        }
1355 313
        $this->cellXfCollection = array_values($this->cellXfCollection);
1356
1357
        // update the index for all cellXfs
1358 313
        foreach ($this->cellXfCollection as $i => $cellXf) {
1359 313
            $cellXf->setIndex($i);
1360
        }
1361
1362
        // make sure there is always at least one cellXf (there should be)
1363 313
        if (empty($this->cellXfCollection)) {
1364
            $this->cellXfCollection[] = new Style();
1365
        }
1366
1367
        // update the xfIndex for all cells, row dimensions, column dimensions
1368 313
        foreach ($this->getWorksheetIterator() as $sheet) {
1369
            // for all cells
1370 313
            foreach ($sheet->getCoordinates(false) as $coordinate) {
1371 303
                $cell = $sheet->getCell($coordinate);
1372 303
                $cell->setXfIndex($map[$cell->getXfIndex()]);
1373
            }
1374
1375
            // for all row dimensions
1376 313
            foreach ($sheet->getRowDimensions() as $rowDimension) {
1377 52
                if ($rowDimension->getXfIndex() !== null) {
1378
                    $rowDimension->setXfIndex($map[$rowDimension->getXfIndex()]);
1379
                }
1380
            }
1381
1382
            // for all column dimensions
1383 313
            foreach ($sheet->getColumnDimensions() as $columnDimension) {
1384 42
                $columnDimension->setXfIndex($map[$columnDimension->getXfIndex()]);
1385
            }
1386
1387
            // also do garbage collection for all the sheets
1388 313
            $sheet->garbageCollect();
1389
        }
1390 313
    }
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 128
    public function getShowHorizontalScroll()
1408
    {
1409 128
        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 61
    public function setShowHorizontalScroll($showHorizontalScroll): void
1418
    {
1419 61
        $this->showHorizontalScroll = (bool) $showHorizontalScroll;
1420 61
    }
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 128
    public function getShowVerticalScroll()
1428
    {
1429 128
        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 61
    public function setShowVerticalScroll($showVerticalScroll): void
1438
    {
1439 61
        $this->showVerticalScroll = (bool) $showVerticalScroll;
1440 61
    }
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 128
    public function getShowSheetTabs()
1448
    {
1449 128
        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 61
    public function setShowSheetTabs($showSheetTabs): void
1458
    {
1459 61
        $this->showSheetTabs = (bool) $showSheetTabs;
1460 61
    }
1461
1462
    /**
1463
     * Return whether the workbook window is minimized.
1464
     *
1465
     * @return bool true if workbook window is minimized
1466
     */
1467 128
    public function getMinimized()
1468
    {
1469 128
        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 61
    public function setMinimized($minimized): void
1478
    {
1479 61
        $this->minimized = (bool) $minimized;
1480 61
    }
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 128
    public function getAutoFilterDateGrouping()
1489
    {
1490 128
        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 61
    public function setAutoFilterDateGrouping($autoFilterDateGrouping): void
1500
    {
1501 61
        $this->autoFilterDateGrouping = (bool) $autoFilterDateGrouping;
1502 61
    }
1503
1504
    /**
1505
     * Return the first sheet in the book view.
1506
     *
1507
     * @return int First sheet in book view
1508
     */
1509 128
    public function getFirstSheetIndex()
1510
    {
1511 128
        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 61
    public function setFirstSheetIndex($firstSheetIndex): void
1520
    {
1521 61
        if ($firstSheetIndex >= 0) {
1522 61
            $this->firstSheetIndex = (int) $firstSheetIndex;
1523
        } else {
1524
            throw new Exception('First sheet index must be a positive integer.');
1525
        }
1526 61
    }
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 128
    public function getVisibility()
1537
    {
1538 128
        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 61
    public function setVisibility($visibility): void
1557
    {
1558 61
        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 61
        if (in_array($visibility, self::$workbookViewVisibilityValues)) {
1563 61
            $this->visibility = $visibility;
1564
        } else {
1565
            throw new Exception('Invalid visibility value.');
1566
        }
1567 61
    }
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 128
    public function getTabRatio()
1576
    {
1577 128
        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 61
    public function setTabRatio($tabRatio): void
1587
    {
1588 61
        if ($tabRatio >= 0 || $tabRatio <= 1000) {
1589 61
            $this->tabRatio = (int) $tabRatio;
1590
        } else {
1591
            throw new Exception('Tab ratio must be between 0 and 1000.');
1592
        }
1593 61
    }
1594
}
1595