Failed Conditions
Push — master ( b01a48...e5185e )
by Adrien
190:50 queued 106:17
created

Spreadsheet::setShowHorizontalScroll()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 2
cts 2
cp 1
crap 1
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 134
    public function hasMacros()
208
    {
209 134
        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 134
    public function getUnparsedLoadedData()
350
    {
351 134
        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 133
    public function setUnparsedLoadedData(array $unparsedLoadedData): void
361
    {
362 133
        $this->unparsedLoadedData = $unparsedLoadedData;
363 133
    }
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 133
    public function hasRibbon()
425
    {
426 133
        return $this->ribbonXMLData !== null;
427
    }
428
429
    /**
430
     * This workbook have additionnal object for the ribbon ?
431
     *
432
     * @return bool
433
     */
434 133
    public function hasRibbonBinObjects()
435
    {
436 133
        return $this->ribbonBinObjects !== null;
437
    }
438
439
    /**
440
     * Check if a sheet with a specified code name already exists.
441
     *
442
     * @param string $pSheetCodeName Name of the worksheet to check
443
     *
444
     * @return bool
445
     */
446 4111
    public function sheetCodeNameExists($pSheetCodeName)
447
    {
448 4111
        return $this->getSheetByCodeName($pSheetCodeName) !== null;
449
    }
450
451
    /**
452
     * Get sheet by code name. Warning : sheet don't have always a code name !
453
     *
454
     * @param string $pName Sheet name
455
     *
456
     * @return null|Worksheet
457
     */
458 4111
    public function getSheetByCodeName($pName)
459
    {
460 4111
        $worksheetCount = count($this->workSheetCollection);
461 4111
        for ($i = 0; $i < $worksheetCount; ++$i) {
462 259
            if ($this->workSheetCollection[$i]->getCodeName() == $pName) {
463 169
                return $this->workSheetCollection[$i];
464
            }
465
        }
466
467 4111
        return null;
468
    }
469
470
    /**
471
     * Create a new PhpSpreadsheet with one Worksheet.
472
     */
473 4111
    public function __construct()
474
    {
475 4111
        $this->uniqueID = uniqid('', true);
476 4111
        $this->calculationEngine = new Calculation($this);
477
478
        // Initialise worksheet collection and add one worksheet
479 4111
        $this->workSheetCollection = [];
480 4111
        $this->workSheetCollection[] = new Worksheet($this);
481 4111
        $this->activeSheetIndex = 0;
482
483
        // Create document properties
484 4111
        $this->properties = new Document\Properties();
485
486
        // Create document security
487 4111
        $this->security = new Document\Security();
488
489
        // Set defined names
490 4111
        $this->definedNames = [];
491
492
        // Create the cellXf supervisor
493 4111
        $this->cellXfSupervisor = new Style(true);
494 4111
        $this->cellXfSupervisor->bindParent($this);
495
496
        // Create the default style
497 4111
        $this->addCellXf(new Style());
498 4111
        $this->addCellStyleXf(new Style());
499 4111
    }
500
501
    /**
502
     * Code to execute when this worksheet is unset().
503
     */
504 31
    public function __destruct()
505
    {
506 31
        $this->disconnectWorksheets();
507 31
        $this->calculationEngine = null;
508 31
        $this->cellXfCollection = [];
509 31
        $this->cellStyleXfCollection = [];
510 31
    }
511
512
    /**
513
     * Disconnect all worksheets from this PhpSpreadsheet workbook object,
514
     * typically so that the PhpSpreadsheet object can be unset.
515
     */
516 2477
    public function disconnectWorksheets(): void
517
    {
518 2477
        foreach ($this->workSheetCollection as $worksheet) {
519 2477
            $worksheet->disconnectCells();
520 2477
            unset($worksheet);
521
        }
522 2477
        $this->workSheetCollection = [];
523 2477
    }
524
525
    /**
526
     * Return the calculation engine for this worksheet.
527
     *
528
     * @return null|Calculation
529
     */
530 4111
    public function getCalculationEngine()
531
    {
532 4111
        return $this->calculationEngine;
533
    }
534
535
    /**
536
     * Get properties.
537
     *
538
     * @return Document\Properties
539
     */
540 446
    public function getProperties()
541
    {
542 446
        return $this->properties;
543
    }
544
545
    /**
546
     * Set properties.
547
     */
548
    public function setProperties(Document\Properties $pValue): void
549
    {
550
        $this->properties = $pValue;
551
    }
552
553
    /**
554
     * Get security.
555
     *
556
     * @return Document\Security
557
     */
558 133
    public function getSecurity()
559
    {
560 133
        return $this->security;
561
    }
562
563
    /**
564
     * Set security.
565
     */
566
    public function setSecurity(Document\Security $pValue): void
567
    {
568
        $this->security = $pValue;
569
    }
570
571
    /**
572
     * Get active sheet.
573
     *
574
     * @return Worksheet
575
     */
576 4076
    public function getActiveSheet()
577
    {
578 4076
        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 359
    public function createSheet($sheetIndex = null)
589
    {
590 359
        $newSheet = new Worksheet($this);
591 359
        $this->addSheet($newSheet, $sheetIndex);
592
593 359
        return $newSheet;
594
    }
595
596
    /**
597
     * Check if a sheet with a specified name already exists.
598
     *
599
     * @param string $pSheetName Name of the worksheet to check
600
     *
601
     * @return bool
602
     */
603 4111
    public function sheetNameExists($pSheetName)
604
    {
605 4111
        return $this->getSheetByName($pSheetName) !== null;
606
    }
607
608
    /**
609
     * Add sheet.
610
     *
611
     * @param null|int $iSheetIndex Index where sheet should go (0,1,..., or null for last)
612
     *
613
     * @return Worksheet
614
     */
615 432
    public function addSheet(Worksheet $pSheet, $iSheetIndex = null)
616
    {
617 432
        if ($this->sheetNameExists($pSheet->getTitle())) {
618 1
            throw new Exception(
619 1
                "Workbook already contains a worksheet named '{$pSheet->getTitle()}'. Rename this worksheet first."
620
            );
621
        }
622
623 432
        if ($iSheetIndex === null) {
624 403
            if ($this->activeSheetIndex < 0) {
625 198
                $this->activeSheetIndex = 0;
626
            }
627 403
            $this->workSheetCollection[] = $pSheet;
628
        } else {
629
            // Insert the sheet at the requested index
630 32
            array_splice(
631 32
                $this->workSheetCollection,
632
                $iSheetIndex,
633 32
                0,
634 32
                [$pSheet]
635
            );
636
637
            // Adjust active sheet index if necessary
638 32
            if ($this->activeSheetIndex >= $iSheetIndex) {
639 28
                ++$this->activeSheetIndex;
640
            }
641
        }
642
643 432
        if ($pSheet->getParent() === null) {
644 45
            $pSheet->rebindParent($this);
645
        }
646
647 432
        return $pSheet;
648
    }
649
650
    /**
651
     * Remove sheet by index.
652
     *
653
     * @param int $pIndex Active sheet index
654
     */
655 206
    public function removeSheetByIndex($pIndex): void
656
    {
657 206
        $numSheets = count($this->workSheetCollection);
658 206
        if ($pIndex > $numSheets - 1) {
659 1
            throw new Exception(
660 1
                "You tried to remove a sheet by the out of bounds index: {$pIndex}. The actual number of sheets is {$numSheets}."
661
            );
662
        }
663 205
        array_splice($this->workSheetCollection, $pIndex, 1);
664
665
        // Adjust active sheet index if necessary
666
        if (
667 205
            ($this->activeSheetIndex >= $pIndex) &&
668 205
            ($this->activeSheetIndex > 0 || $numSheets <= 1)
669
        ) {
670 203
            --$this->activeSheetIndex;
671
        }
672 205
    }
673
674
    /**
675
     * Get sheet by index.
676
     *
677
     * @param int $pIndex Sheet index
678
     *
679
     * @return Worksheet
680
     */
681 4092
    public function getSheet($pIndex)
682
    {
683 4092
        if (!isset($this->workSheetCollection[$pIndex])) {
684 1
            $numSheets = $this->getSheetCount();
685
686 1
            throw new Exception(
687 1
                "Your requested sheet index: {$pIndex} is out of bounds. The actual number of sheets is {$numSheets}."
688
            );
689
        }
690
691 4092
        return $this->workSheetCollection[$pIndex];
692
    }
693
694
    /**
695
     * Get all sheets.
696
     *
697
     * @return Worksheet[]
698
     */
699 78
    public function getAllSheets()
700
    {
701 78
        return $this->workSheetCollection;
702
    }
703
704
    /**
705
     * Get sheet by name.
706
     *
707
     * @param string $pName Sheet name
708
     *
709
     * @return null|Worksheet
710
     */
711 4111
    public function getSheetByName($pName)
712
    {
713 4111
        $worksheetCount = count($this->workSheetCollection);
714 4111
        for ($i = 0; $i < $worksheetCount; ++$i) {
715 3808
            if ($this->workSheetCollection[$i]->getTitle() === trim($pName, "'")) {
716 3621
                return $this->workSheetCollection[$i];
717
            }
718
        }
719
720 4111
        return null;
721
    }
722
723
    /**
724
     * Get index for sheet.
725
     *
726
     * @return int index
727
     */
728 3902
    public function getIndex(Worksheet $pSheet)
729
    {
730 3902
        foreach ($this->workSheetCollection as $key => $value) {
731 3902
            if ($value->getHashCode() === $pSheet->getHashCode()) {
732 3901
                return $key;
733
            }
734
        }
735
736 1
        throw new Exception('Sheet does not exist.');
737
    }
738
739
    /**
740
     * Set index for sheet by sheet name.
741
     *
742
     * @param string $sheetName Sheet name to modify index for
743
     * @param int $newIndex New index for the sheet
744
     *
745
     * @return int New sheet index
746
     */
747 1
    public function setIndexByName($sheetName, $newIndex)
748
    {
749 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

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