Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Style;
4
 
5
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
6
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
7
use PhpOffice\PhpSpreadsheet\Exception;
8
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
9
use PhpOffice\PhpSpreadsheet\Spreadsheet;
10
 
11
class Style extends Supervisor
12
{
13
    /**
14
     * Font.
15
     *
16
     * @var Font
17
     */
18
    protected $font;
19
 
20
    /**
21
     * Fill.
22
     *
23
     * @var Fill
24
     */
25
    protected $fill;
26
 
27
    /**
28
     * Borders.
29
     *
30
     * @var Borders
31
     */
32
    protected $borders;
33
 
34
    /**
35
     * Alignment.
36
     *
37
     * @var Alignment
38
     */
39
    protected $alignment;
40
 
41
    /**
42
     * Number Format.
43
     *
44
     * @var NumberFormat
45
     */
46
    protected $numberFormat;
47
 
48
    /**
49
     * Protection.
50
     *
51
     * @var Protection
52
     */
53
    protected $protection;
54
 
55
    /**
56
     * Index of style in collection. Only used for real style.
57
     *
58
     * @var int
59
     */
60
    protected $index;
61
 
62
    /**
63
     * Use Quote Prefix when displaying in cell editor. Only used for real style.
64
     *
65
     * @var bool
66
     */
67
    protected $quotePrefix = false;
68
 
69
    /**
70
     * Internal cache for styles
71
     * Used when applying style on range of cells (column or row) and cleared when
72
     * all cells in range is styled.
73
     *
74
     * PhpSpreadsheet will always minimize the amount of styles used. So cells with
75
     * same styles will reference the same Style instance. To check if two styles
76
     * are similar Style::getHashCode() is used. This call is expensive. To minimize
77
     * the need to call this method we can cache the internal PHP object id of the
78
     * Style in the range. Style::getHashCode() will then only be called when we
79
     * encounter a unique style.
80
     *
81
     * @see Style::applyFromArray()
82
     * @see Style::getHashCode()
83
     *
84
     * @var null|array<string, array>
85
     */
86
    private static $cachedStyles;
87
 
88
    /**
89
     * Create a new Style.
90
     *
91
     * @param bool $isSupervisor Flag indicating if this is a supervisor or not
92
     *         Leave this value at default unless you understand exactly what
93
     *    its ramifications are
94
     * @param bool $isConditional Flag indicating if this is a conditional style or not
95
     *       Leave this value at default unless you understand exactly what
96
     *    its ramifications are
97
     */
98
    public function __construct($isSupervisor = false, $isConditional = false)
99
    {
100
        parent::__construct($isSupervisor);
101
 
102
        // Initialise values
103
        $this->font = new Font($isSupervisor, $isConditional);
104
        $this->fill = new Fill($isSupervisor, $isConditional);
105
        $this->borders = new Borders($isSupervisor, $isConditional);
106
        $this->alignment = new Alignment($isSupervisor, $isConditional);
107
        $this->numberFormat = new NumberFormat($isSupervisor, $isConditional);
108
        $this->protection = new Protection($isSupervisor, $isConditional);
109
 
110
        // bind parent if we are a supervisor
111
        if ($isSupervisor) {
112
            $this->font->bindParent($this);
113
            $this->fill->bindParent($this);
114
            $this->borders->bindParent($this);
115
            $this->alignment->bindParent($this);
116
            $this->numberFormat->bindParent($this);
117
            $this->protection->bindParent($this);
118
        }
119
    }
120
 
121
    /**
122
     * Get the shared style component for the currently active cell in currently active sheet.
123
     * Only used for style supervisor.
124
     */
125
    public function getSharedComponent(): self
126
    {
127
        $activeSheet = $this->getActiveSheet();
128
        $selectedCell = Functions::trimSheetFromCellReference($this->getActiveCell()); // e.g. 'A1'
129
 
130
        if ($activeSheet->cellExists($selectedCell)) {
131
            $xfIndex = $activeSheet->getCell($selectedCell)->getXfIndex();
132
        } else {
133
            $xfIndex = 0;
134
        }
135
 
136
        return $activeSheet->getParentOrThrow()->getCellXfByIndex($xfIndex);
137
    }
138
 
139
    /**
140
     * Get parent. Only used for style supervisor.
141
     */
142
    public function getParent(): Spreadsheet
143
    {
144
        return $this->getActiveSheet()->getParentOrThrow();
145
    }
146
 
147
    /**
148
     * Build style array from subcomponents.
149
     *
150
     * @param array $array
151
     *
152
     * @return array
153
     */
154
    public function getStyleArray($array)
155
    {
156
        return ['quotePrefix' => $array];
157
    }
158
 
159
    /**
160
     * Apply styles from array.
161
     *
162
     * <code>
163
     * $spreadsheet->getActiveSheet()->getStyle('B2')->applyFromArray(
164
     *     [
165
     *         'font' => [
166
     *             'name' => 'Arial',
167
     *             'bold' => true,
168
     *             'italic' => false,
169
     *             'underline' => Font::UNDERLINE_DOUBLE,
170
     *             'strikethrough' => false,
171
     *             'color' => [
172
     *                 'rgb' => '808080'
173
     *             ]
174
     *         ],
175
     *         'borders' => [
176
     *             'bottom' => [
177
     *                 'borderStyle' => Border::BORDER_DASHDOT,
178
     *                 'color' => [
179
     *                     'rgb' => '808080'
180
     *                 ]
181
     *             ],
182
     *             'top' => [
183
     *                 'borderStyle' => Border::BORDER_DASHDOT,
184
     *                 'color' => [
185
     *                     'rgb' => '808080'
186
     *                 ]
187
     *             ]
188
     *         ],
189
     *         'alignment' => [
190
     *             'horizontal' => Alignment::HORIZONTAL_CENTER,
191
     *             'vertical' => Alignment::VERTICAL_CENTER,
192
     *             'wrapText' => true,
193
     *         ],
194
     *         'quotePrefix'    => true
195
     *     ]
196
     * );
197
     * </code>
198
     *
199
     * @param array $styleArray Array containing style information
200
     * @param bool $advancedBorders advanced mode for setting borders
201
     *
202
     * @return $this
203
     */
204
    public function applyFromArray(array $styleArray, $advancedBorders = true)
205
    {
206
        if ($this->isSupervisor) {
207
            $pRange = $this->getSelectedCells();
208
 
209
            // Uppercase coordinate and strip any Worksheet reference from the selected range
210
            $pRange = strtoupper($pRange);
211
            if (strpos($pRange, '!') !== false) {
212
                $pRangeWorksheet = StringHelper::strToUpper(trim(substr($pRange, 0, (int) strrpos($pRange, '!')), "'"));
213
                if ($pRangeWorksheet !== '' && StringHelper::strToUpper($this->getActiveSheet()->getTitle()) !== $pRangeWorksheet) {
214
                    throw new Exception('Invalid Worksheet for specified Range');
215
                }
216
                $pRange = strtoupper(Functions::trimSheetFromCellReference($pRange));
217
            }
218
 
219
            // Is it a cell range or a single cell?
220
            if (strpos($pRange, ':') === false) {
221
                $rangeA = $pRange;
222
                $rangeB = $pRange;
223
            } else {
224
                [$rangeA, $rangeB] = explode(':', $pRange);
225
            }
226
 
227
            // Calculate range outer borders
228
            $rangeStart = Coordinate::coordinateFromString($rangeA);
229
            $rangeEnd = Coordinate::coordinateFromString($rangeB);
230
            $rangeStartIndexes = Coordinate::indexesFromString($rangeA);
231
            $rangeEndIndexes = Coordinate::indexesFromString($rangeB);
232
 
233
            $columnStart = $rangeStart[0];
234
            $columnEnd = $rangeEnd[0];
235
 
236
            // Make sure we can loop upwards on rows and columns
237
            if ($rangeStartIndexes[0] > $rangeEndIndexes[0] && $rangeStartIndexes[1] > $rangeEndIndexes[1]) {
238
                $tmp = $rangeStartIndexes;
239
                $rangeStartIndexes = $rangeEndIndexes;
240
                $rangeEndIndexes = $tmp;
241
            }
242
 
243
            // ADVANCED MODE:
244
            if ($advancedBorders && isset($styleArray['borders'])) {
245
                // 'allBorders' is a shorthand property for 'outline' and 'inside' and
246
                //        it applies to components that have not been set explicitly
247
                if (isset($styleArray['borders']['allBorders'])) {
248
                    foreach (['outline', 'inside'] as $component) {
249
                        if (!isset($styleArray['borders'][$component])) {
250
                            $styleArray['borders'][$component] = $styleArray['borders']['allBorders'];
251
                        }
252
                    }
253
                    unset($styleArray['borders']['allBorders']); // not needed any more
254
                }
255
                // 'outline' is a shorthand property for 'top', 'right', 'bottom', 'left'
256
                //        it applies to components that have not been set explicitly
257
                if (isset($styleArray['borders']['outline'])) {
258
                    foreach (['top', 'right', 'bottom', 'left'] as $component) {
259
                        if (!isset($styleArray['borders'][$component])) {
260
                            $styleArray['borders'][$component] = $styleArray['borders']['outline'];
261
                        }
262
                    }
263
                    unset($styleArray['borders']['outline']); // not needed any more
264
                }
265
                // 'inside' is a shorthand property for 'vertical' and 'horizontal'
266
                //        it applies to components that have not been set explicitly
267
                if (isset($styleArray['borders']['inside'])) {
268
                    foreach (['vertical', 'horizontal'] as $component) {
269
                        if (!isset($styleArray['borders'][$component])) {
270
                            $styleArray['borders'][$component] = $styleArray['borders']['inside'];
271
                        }
272
                    }
273
                    unset($styleArray['borders']['inside']); // not needed any more
274
                }
275
                // width and height characteristics of selection, 1, 2, or 3 (for 3 or more)
276
                $xMax = min($rangeEndIndexes[0] - $rangeStartIndexes[0] + 1, 3);
277
                $yMax = min($rangeEndIndexes[1] - $rangeStartIndexes[1] + 1, 3);
278
 
279
                // loop through up to 3 x 3 = 9 regions
280
                for ($x = 1; $x <= $xMax; ++$x) {
281
                    // start column index for region
282
                    $colStart = ($x == 3) ?
283
                        Coordinate::stringFromColumnIndex($rangeEndIndexes[0])
284
                        : Coordinate::stringFromColumnIndex($rangeStartIndexes[0] + $x - 1);
285
                    // end column index for region
286
                    $colEnd = ($x == 1) ?
287
                        Coordinate::stringFromColumnIndex($rangeStartIndexes[0])
288
                        : Coordinate::stringFromColumnIndex($rangeEndIndexes[0] - $xMax + $x);
289
 
290
                    for ($y = 1; $y <= $yMax; ++$y) {
291
                        // which edges are touching the region
292
                        $edges = [];
293
                        if ($x == 1) {
294
                            // are we at left edge
295
                            $edges[] = 'left';
296
                        }
297
                        if ($x == $xMax) {
298
                            // are we at right edge
299
                            $edges[] = 'right';
300
                        }
301
                        if ($y == 1) {
302
                            // are we at top edge?
303
                            $edges[] = 'top';
304
                        }
305
                        if ($y == $yMax) {
306
                            // are we at bottom edge?
307
                            $edges[] = 'bottom';
308
                        }
309
 
310
                        // start row index for region
311
                        $rowStart = ($y == 3) ?
312
                            $rangeEndIndexes[1] : $rangeStartIndexes[1] + $y - 1;
313
 
314
                        // end row index for region
315
                        $rowEnd = ($y == 1) ?
316
                            $rangeStartIndexes[1] : $rangeEndIndexes[1] - $yMax + $y;
317
 
318
                        // build range for region
319
                        $range = $colStart . $rowStart . ':' . $colEnd . $rowEnd;
320
 
321
                        // retrieve relevant style array for region
322
                        $regionStyles = $styleArray;
323
                        unset($regionStyles['borders']['inside']);
324
 
325
                        // what are the inner edges of the region when looking at the selection
326
                        $innerEdges = array_diff(['top', 'right', 'bottom', 'left'], $edges);
327
 
328
                        // inner edges that are not touching the region should take the 'inside' border properties if they have been set
329
                        foreach ($innerEdges as $innerEdge) {
330
                            switch ($innerEdge) {
331
                                case 'top':
332
                                case 'bottom':
333
                                    // should pick up 'horizontal' border property if set
334
                                    if (isset($styleArray['borders']['horizontal'])) {
335
                                        $regionStyles['borders'][$innerEdge] = $styleArray['borders']['horizontal'];
336
                                    } else {
337
                                        unset($regionStyles['borders'][$innerEdge]);
338
                                    }
339
 
340
                                    break;
341
                                case 'left':
342
                                case 'right':
343
                                    // should pick up 'vertical' border property if set
344
                                    if (isset($styleArray['borders']['vertical'])) {
345
                                        $regionStyles['borders'][$innerEdge] = $styleArray['borders']['vertical'];
346
                                    } else {
347
                                        unset($regionStyles['borders'][$innerEdge]);
348
                                    }
349
 
350
                                    break;
351
                            }
352
                        }
353
 
354
                        // apply region style to region by calling applyFromArray() in simple mode
355
                        $this->getActiveSheet()->getStyle($range)->applyFromArray($regionStyles, false);
356
                    }
357
                }
358
 
359
                // restore initial cell selection range
360
                $this->getActiveSheet()->getStyle($pRange);
361
 
362
                return $this;
363
            }
364
 
365
            // SIMPLE MODE:
366
            // Selection type, inspect
367
            if (preg_match('/^[A-Z]+1:[A-Z]+1048576$/', $pRange)) {
368
                $selectionType = 'COLUMN';
369
 
370
                // Enable caching of styles
371
                self::$cachedStyles = ['hashByObjId' => [], 'styleByHash' => []];
372
            } elseif (preg_match('/^A\d+:XFD\d+$/', $pRange)) {
373
                $selectionType = 'ROW';
374
 
375
                // Enable caching of styles
376
                self::$cachedStyles = ['hashByObjId' => [], 'styleByHash' => []];
377
            } else {
378
                $selectionType = 'CELL';
379
            }
380
 
381
            // First loop through columns, rows, or cells to find out which styles are affected by this operation
382
            $oldXfIndexes = $this->getOldXfIndexes($selectionType, $rangeStartIndexes, $rangeEndIndexes, $columnStart, $columnEnd, $styleArray);
383
 
384
            // clone each of the affected styles, apply the style array, and add the new styles to the workbook
385
            $workbook = $this->getActiveSheet()->getParentOrThrow();
386
            $newXfIndexes = [];
387
            foreach ($oldXfIndexes as $oldXfIndex => $dummy) {
388
                $style = $workbook->getCellXfByIndex($oldXfIndex);
389
 
390
                // $cachedStyles is set when applying style for a range of cells, either column or row
391
                if (self::$cachedStyles === null) {
392
                    // Clone the old style and apply style-array
393
                    $newStyle = clone $style;
394
                    $newStyle->applyFromArray($styleArray);
395
 
396
                    // Look for existing style we can use instead (reduce memory usage)
397
                    $existingStyle = $workbook->getCellXfByHashCode($newStyle->getHashCode());
398
                } else {
399
                    // Style cache is stored by Style::getHashCode(). But calling this method is
400
                    // expensive. So we cache the php obj id -> hash.
401
                    $objId = spl_object_id($style);
402
 
403
                    // Look for the original HashCode
404
                    $styleHash = self::$cachedStyles['hashByObjId'][$objId] ?? null;
405
                    if ($styleHash === null) {
406
                        // This object_id is not cached, store the hashcode in case encounter again
407
                        $styleHash = self::$cachedStyles['hashByObjId'][$objId] = $style->getHashCode();
408
                    }
409
 
410
                    // Find existing style by hash.
411
                    $existingStyle = self::$cachedStyles['styleByHash'][$styleHash] ?? null;
412
 
413
                    if (!$existingStyle) {
414
                        // The old style combined with the new style array is not cached, so we create it now
415
                        $newStyle = clone $style;
416
                        $newStyle->applyFromArray($styleArray);
417
 
418
                        // Look for similar style in workbook to reduce memory usage
419
                        $existingStyle = $workbook->getCellXfByHashCode($newStyle->getHashCode());
420
 
421
                        // Cache the new style by original hashcode
422
                        self::$cachedStyles['styleByHash'][$styleHash] = $existingStyle instanceof self ? $existingStyle : $newStyle;
423
                    }
424
                }
425
 
426
                if ($existingStyle) {
427
                    // there is already such cell Xf in our collection
428
                    $newXfIndexes[$oldXfIndex] = $existingStyle->getIndex();
429
                } else {
430
                    if (!isset($newStyle)) {
431
                        // Handle bug in PHPStan, see https://github.com/phpstan/phpstan/issues/5805
432
                        // $newStyle should always be defined.
433
                        // This block might not be needed in the future
434
                        // @codeCoverageIgnoreStart
435
                        $newStyle = clone $style;
436
                        $newStyle->applyFromArray($styleArray);
437
                        // @codeCoverageIgnoreEnd
438
                    }
439
 
440
                    // we don't have such a cell Xf, need to add
441
                    $workbook->addCellXf($newStyle);
442
                    $newXfIndexes[$oldXfIndex] = $newStyle->getIndex();
443
                }
444
            }
445
 
446
            // Loop through columns, rows, or cells again and update the XF index
447
            switch ($selectionType) {
448
                case 'COLUMN':
449
                    for ($col = $rangeStartIndexes[0]; $col <= $rangeEndIndexes[0]; ++$col) {
450
                        $columnDimension = $this->getActiveSheet()->getColumnDimensionByColumn($col);
451
                        $oldXfIndex = $columnDimension->getXfIndex();
452
                        $columnDimension->setXfIndex($newXfIndexes[$oldXfIndex]);
453
                    }
454
 
455
                    // Disable caching of styles
456
                    self::$cachedStyles = null;
457
 
458
                    break;
459
                case 'ROW':
460
                    for ($row = $rangeStartIndexes[1]; $row <= $rangeEndIndexes[1]; ++$row) {
461
                        $rowDimension = $this->getActiveSheet()->getRowDimension($row);
462
                        // row without explicit style should be formatted based on default style
463
                        $oldXfIndex = $rowDimension->getXfIndex() ?? 0;
464
                        $rowDimension->setXfIndex($newXfIndexes[$oldXfIndex]);
465
                    }
466
 
467
                    // Disable caching of styles
468
                    self::$cachedStyles = null;
469
 
470
                    break;
471
                case 'CELL':
472
                    for ($col = $rangeStartIndexes[0]; $col <= $rangeEndIndexes[0]; ++$col) {
473
                        for ($row = $rangeStartIndexes[1]; $row <= $rangeEndIndexes[1]; ++$row) {
474
                            $cell = $this->getActiveSheet()->getCell([$col, $row]);
475
                            $oldXfIndex = $cell->getXfIndex();
476
                            $cell->setXfIndex($newXfIndexes[$oldXfIndex]);
477
                        }
478
                    }
479
 
480
                    break;
481
            }
482
        } else {
483
            // not a supervisor, just apply the style array directly on style object
484
            if (isset($styleArray['fill'])) {
485
                $this->getFill()->applyFromArray($styleArray['fill']);
486
            }
487
            if (isset($styleArray['font'])) {
488
                $this->getFont()->applyFromArray($styleArray['font']);
489
            }
490
            if (isset($styleArray['borders'])) {
491
                $this->getBorders()->applyFromArray($styleArray['borders']);
492
            }
493
            if (isset($styleArray['alignment'])) {
494
                $this->getAlignment()->applyFromArray($styleArray['alignment']);
495
            }
496
            if (isset($styleArray['numberFormat'])) {
497
                $this->getNumberFormat()->applyFromArray($styleArray['numberFormat']);
498
            }
499
            if (isset($styleArray['protection'])) {
500
                $this->getProtection()->applyFromArray($styleArray['protection']);
501
            }
502
            if (isset($styleArray['quotePrefix'])) {
503
                $this->quotePrefix = $styleArray['quotePrefix'];
504
            }
505
        }
506
 
507
        return $this;
508
    }
509
 
510
    private function getOldXfIndexes(string $selectionType, array $rangeStart, array $rangeEnd, string $columnStart, string $columnEnd, array $styleArray): array
511
    {
512
        $oldXfIndexes = [];
513
        switch ($selectionType) {
514
            case 'COLUMN':
515
                for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
516
                    $oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true;
517
                }
518
                foreach ($this->getActiveSheet()->getColumnIterator($columnStart, $columnEnd) as $columnIterator) {
519
                    $cellIterator = $columnIterator->getCellIterator();
520
                    $cellIterator->setIterateOnlyExistingCells(true);
521
                    foreach ($cellIterator as $columnCell) {
522
                        if ($columnCell !== null) {
523
                            $columnCell->getStyle()->applyFromArray($styleArray);
524
                        }
525
                    }
526
                }
527
 
528
                break;
529
            case 'ROW':
530
                for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
531
                    if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() === null) {
532
                        $oldXfIndexes[0] = true; // row without explicit style should be formatted based on default style
533
                    } else {
534
                        $oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true;
535
                    }
536
                }
537
                foreach ($this->getActiveSheet()->getRowIterator((int) $rangeStart[1], (int) $rangeEnd[1]) as $rowIterator) {
538
                    $cellIterator = $rowIterator->getCellIterator();
539
                    $cellIterator->setIterateOnlyExistingCells(true);
540
                    foreach ($cellIterator as $rowCell) {
541
                        if ($rowCell !== null) {
542
                            $rowCell->getStyle()->applyFromArray($styleArray);
543
                        }
544
                    }
545
                }
546
 
547
                break;
548
            case 'CELL':
549
                for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
550
                    for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
551
                        $oldXfIndexes[$this->getActiveSheet()->getCell([$col, $row])->getXfIndex()] = true;
552
                    }
553
                }
554
 
555
                break;
556
        }
557
 
558
        return $oldXfIndexes;
559
    }
560
 
561
    /**
562
     * Get Fill.
563
     *
564
     * @return Fill
565
     */
566
    public function getFill()
567
    {
568
        return $this->fill;
569
    }
570
 
571
    /**
572
     * Get Font.
573
     *
574
     * @return Font
575
     */
576
    public function getFont()
577
    {
578
        return $this->font;
579
    }
580
 
581
    /**
582
     * Set font.
583
     *
584
     * @return $this
585
     */
586
    public function setFont(Font $font)
587
    {
588
        $this->font = $font;
589
 
590
        return $this;
591
    }
592
 
593
    /**
594
     * Get Borders.
595
     *
596
     * @return Borders
597
     */
598
    public function getBorders()
599
    {
600
        return $this->borders;
601
    }
602
 
603
    /**
604
     * Get Alignment.
605
     *
606
     * @return Alignment
607
     */
608
    public function getAlignment()
609
    {
610
        return $this->alignment;
611
    }
612
 
613
    /**
614
     * Get Number Format.
615
     *
616
     * @return NumberFormat
617
     */
618
    public function getNumberFormat()
619
    {
620
        return $this->numberFormat;
621
    }
622
 
623
    /**
624
     * Get Conditional Styles. Only used on supervisor.
625
     *
626
     * @return Conditional[]
627
     */
628
    public function getConditionalStyles()
629
    {
630
        return $this->getActiveSheet()->getConditionalStyles($this->getActiveCell());
631
    }
632
 
633
    /**
634
     * Set Conditional Styles. Only used on supervisor.
635
     *
636
     * @param Conditional[] $conditionalStyleArray Array of conditional styles
637
     *
638
     * @return $this
639
     */
640
    public function setConditionalStyles(array $conditionalStyleArray)
641
    {
642
        $this->getActiveSheet()->setConditionalStyles($this->getSelectedCells(), $conditionalStyleArray);
643
 
644
        return $this;
645
    }
646
 
647
    /**
648
     * Get Protection.
649
     *
650
     * @return Protection
651
     */
652
    public function getProtection()
653
    {
654
        return $this->protection;
655
    }
656
 
657
    /**
658
     * Get quote prefix.
659
     *
660
     * @return bool
661
     */
662
    public function getQuotePrefix()
663
    {
664
        if ($this->isSupervisor) {
665
            return $this->getSharedComponent()->getQuotePrefix();
666
        }
667
 
668
        return $this->quotePrefix;
669
    }
670
 
671
    /**
672
     * Set quote prefix.
673
     *
674
     * @param bool $quotePrefix
675
     *
676
     * @return $this
677
     */
678
    public function setQuotePrefix($quotePrefix)
679
    {
680
        if ($quotePrefix == '') {
681
            $quotePrefix = false;
682
        }
683
        if ($this->isSupervisor) {
684
            $styleArray = ['quotePrefix' => $quotePrefix];
685
            $this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
686
        } else {
687
            $this->quotePrefix = (bool) $quotePrefix;
688
        }
689
 
690
        return $this;
691
    }
692
 
693
    /**
694
     * Get hash code.
695
     *
696
     * @return string Hash code
697
     */
698
    public function getHashCode()
699
    {
700
        return md5(
701
            $this->fill->getHashCode() .
702
            $this->font->getHashCode() .
703
            $this->borders->getHashCode() .
704
            $this->alignment->getHashCode() .
705
            $this->numberFormat->getHashCode() .
706
            $this->protection->getHashCode() .
707
            ($this->quotePrefix ? 't' : 'f') .
708
            __CLASS__
709
        );
710
    }
711
 
712
    /**
713
     * Get own index in style collection.
714
     *
715
     * @return int
716
     */
717
    public function getIndex()
718
    {
719
        return $this->index;
720
    }
721
 
722
    /**
723
     * Set own index in style collection.
724
     *
725
     * @param int $index
726
     */
727
    public function setIndex($index): void
728
    {
729
        $this->index = $index;
730
    }
731
 
732
    protected function exportArray1(): array
733
    {
734
        $exportedArray = [];
735
        $this->exportArray2($exportedArray, 'alignment', $this->getAlignment());
736
        $this->exportArray2($exportedArray, 'borders', $this->getBorders());
737
        $this->exportArray2($exportedArray, 'fill', $this->getFill());
738
        $this->exportArray2($exportedArray, 'font', $this->getFont());
739
        $this->exportArray2($exportedArray, 'numberFormat', $this->getNumberFormat());
740
        $this->exportArray2($exportedArray, 'protection', $this->getProtection());
741
        $this->exportArray2($exportedArray, 'quotePrefx', $this->getQuotePrefix());
742
 
743
        return $exportedArray;
744
    }
745
}