1<?php
2
3namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
4
5use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
6use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
7use PhpOffice\PhpSpreadsheet\Spreadsheet;
8use PhpOffice\PhpSpreadsheet\Style\Border;
9use PhpOffice\PhpSpreadsheet\Style\Borders;
10use PhpOffice\PhpSpreadsheet\Style\Conditional;
11use PhpOffice\PhpSpreadsheet\Style\Fill;
12use PhpOffice\PhpSpreadsheet\Style\Font;
13use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
14use PhpOffice\PhpSpreadsheet\Style\Protection;
15
16class Style extends WriterPart
17{
18    /**
19     * Write styles to XML format.
20     *
21     * @param Spreadsheet $spreadsheet
22     *
23     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
24     *
25     * @return string XML Output
26     */
27    public function writeStyles(Spreadsheet $spreadsheet)
28    {
29        // Create XML writer
30        $objWriter = null;
31        if ($this->getParentWriter()->getUseDiskCaching()) {
32            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
33        } else {
34            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
35        }
36
37        // XML header
38        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
39
40        // styleSheet
41        $objWriter->startElement('styleSheet');
42        $objWriter->writeAttribute('xml:space', 'preserve');
43        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
44
45        // numFmts
46        $objWriter->startElement('numFmts');
47        $objWriter->writeAttribute('count', $this->getParentWriter()->getNumFmtHashTable()->count());
48
49        // numFmt
50        for ($i = 0; $i < $this->getParentWriter()->getNumFmtHashTable()->count(); ++$i) {
51            $this->writeNumFmt($objWriter, $this->getParentWriter()->getNumFmtHashTable()->getByIndex($i), $i);
52        }
53
54        $objWriter->endElement();
55
56        // fonts
57        $objWriter->startElement('fonts');
58        $objWriter->writeAttribute('count', $this->getParentWriter()->getFontHashTable()->count());
59
60        // font
61        for ($i = 0; $i < $this->getParentWriter()->getFontHashTable()->count(); ++$i) {
62            $this->writeFont($objWriter, $this->getParentWriter()->getFontHashTable()->getByIndex($i));
63        }
64
65        $objWriter->endElement();
66
67        // fills
68        $objWriter->startElement('fills');
69        $objWriter->writeAttribute('count', $this->getParentWriter()->getFillHashTable()->count());
70
71        // fill
72        for ($i = 0; $i < $this->getParentWriter()->getFillHashTable()->count(); ++$i) {
73            $this->writeFill($objWriter, $this->getParentWriter()->getFillHashTable()->getByIndex($i));
74        }
75
76        $objWriter->endElement();
77
78        // borders
79        $objWriter->startElement('borders');
80        $objWriter->writeAttribute('count', $this->getParentWriter()->getBordersHashTable()->count());
81
82        // border
83        for ($i = 0; $i < $this->getParentWriter()->getBordersHashTable()->count(); ++$i) {
84            $this->writeBorder($objWriter, $this->getParentWriter()->getBordersHashTable()->getByIndex($i));
85        }
86
87        $objWriter->endElement();
88
89        // cellStyleXfs
90        $objWriter->startElement('cellStyleXfs');
91        $objWriter->writeAttribute('count', 1);
92
93        // xf
94        $objWriter->startElement('xf');
95        $objWriter->writeAttribute('numFmtId', 0);
96        $objWriter->writeAttribute('fontId', 0);
97        $objWriter->writeAttribute('fillId', 0);
98        $objWriter->writeAttribute('borderId', 0);
99        $objWriter->endElement();
100
101        $objWriter->endElement();
102
103        // cellXfs
104        $objWriter->startElement('cellXfs');
105        $objWriter->writeAttribute('count', count($spreadsheet->getCellXfCollection()));
106
107        // xf
108        foreach ($spreadsheet->getCellXfCollection() as $cellXf) {
109            $this->writeCellStyleXf($objWriter, $cellXf, $spreadsheet);
110        }
111
112        $objWriter->endElement();
113
114        // cellStyles
115        $objWriter->startElement('cellStyles');
116        $objWriter->writeAttribute('count', 1);
117
118        // cellStyle
119        $objWriter->startElement('cellStyle');
120        $objWriter->writeAttribute('name', 'Normal');
121        $objWriter->writeAttribute('xfId', 0);
122        $objWriter->writeAttribute('builtinId', 0);
123        $objWriter->endElement();
124
125        $objWriter->endElement();
126
127        // dxfs
128        $objWriter->startElement('dxfs');
129        $objWriter->writeAttribute('count', $this->getParentWriter()->getStylesConditionalHashTable()->count());
130
131        // dxf
132        for ($i = 0; $i < $this->getParentWriter()->getStylesConditionalHashTable()->count(); ++$i) {
133            $this->writeCellStyleDxf($objWriter, $this->getParentWriter()->getStylesConditionalHashTable()->getByIndex($i)->getStyle());
134        }
135
136        $objWriter->endElement();
137
138        // tableStyles
139        $objWriter->startElement('tableStyles');
140        $objWriter->writeAttribute('defaultTableStyle', 'TableStyleMedium9');
141        $objWriter->writeAttribute('defaultPivotStyle', 'PivotTableStyle1');
142        $objWriter->endElement();
143
144        $objWriter->endElement();
145
146        // Return
147        return $objWriter->getData();
148    }
149
150    /**
151     * Write Fill.
152     *
153     * @param XMLWriter $objWriter XML Writer
154     * @param Fill $pFill Fill style
155     */
156    private function writeFill(XMLWriter $objWriter, Fill $pFill)
157    {
158        // Check if this is a pattern type or gradient type
159        if ($pFill->getFillType() === Fill::FILL_GRADIENT_LINEAR ||
160            $pFill->getFillType() === Fill::FILL_GRADIENT_PATH) {
161            // Gradient fill
162            $this->writeGradientFill($objWriter, $pFill);
163        } elseif ($pFill->getFillType() !== null) {
164            // Pattern fill
165            $this->writePatternFill($objWriter, $pFill);
166        }
167    }
168
169    /**
170     * Write Gradient Fill.
171     *
172     * @param XMLWriter $objWriter XML Writer
173     * @param Fill $pFill Fill style
174     */
175    private function writeGradientFill(XMLWriter $objWriter, Fill $pFill)
176    {
177        // fill
178        $objWriter->startElement('fill');
179
180        // gradientFill
181        $objWriter->startElement('gradientFill');
182        $objWriter->writeAttribute('type', $pFill->getFillType());
183        $objWriter->writeAttribute('degree', $pFill->getRotation());
184
185        // stop
186        $objWriter->startElement('stop');
187        $objWriter->writeAttribute('position', '0');
188
189        // color
190        $objWriter->startElement('color');
191        $objWriter->writeAttribute('rgb', $pFill->getStartColor()->getARGB());
192        $objWriter->endElement();
193
194        $objWriter->endElement();
195
196        // stop
197        $objWriter->startElement('stop');
198        $objWriter->writeAttribute('position', '1');
199
200        // color
201        $objWriter->startElement('color');
202        $objWriter->writeAttribute('rgb', $pFill->getEndColor()->getARGB());
203        $objWriter->endElement();
204
205        $objWriter->endElement();
206
207        $objWriter->endElement();
208
209        $objWriter->endElement();
210    }
211
212    /**
213     * Write Pattern Fill.
214     *
215     * @param XMLWriter $objWriter XML Writer
216     * @param Fill $pFill Fill style
217     */
218    private function writePatternFill(XMLWriter $objWriter, Fill $pFill)
219    {
220        // fill
221        $objWriter->startElement('fill');
222
223        // patternFill
224        $objWriter->startElement('patternFill');
225        $objWriter->writeAttribute('patternType', $pFill->getFillType());
226
227        if ($pFill->getFillType() !== Fill::FILL_NONE) {
228            // fgColor
229            if ($pFill->getStartColor()->getARGB()) {
230                $objWriter->startElement('fgColor');
231                $objWriter->writeAttribute('rgb', $pFill->getStartColor()->getARGB());
232                $objWriter->endElement();
233            }
234        }
235        if ($pFill->getFillType() !== Fill::FILL_NONE) {
236            // bgColor
237            if ($pFill->getEndColor()->getARGB()) {
238                $objWriter->startElement('bgColor');
239                $objWriter->writeAttribute('rgb', $pFill->getEndColor()->getARGB());
240                $objWriter->endElement();
241            }
242        }
243
244        $objWriter->endElement();
245
246        $objWriter->endElement();
247    }
248
249    /**
250     * Write Font.
251     *
252     * @param XMLWriter $objWriter XML Writer
253     * @param Font $pFont Font style
254     */
255    private function writeFont(XMLWriter $objWriter, Font $pFont)
256    {
257        // font
258        $objWriter->startElement('font');
259        //    Weird! The order of these elements actually makes a difference when opening Xlsx
260        //        files in Excel2003 with the compatibility pack. It's not documented behaviour,
261        //        and makes for a real WTF!
262
263        // Bold. We explicitly write this element also when false (like MS Office Excel 2007 does
264        // for conditional formatting). Otherwise it will apparently not be picked up in conditional
265        // formatting style dialog
266        if ($pFont->getBold() !== null) {
267            $objWriter->startElement('b');
268            $objWriter->writeAttribute('val', $pFont->getBold() ? '1' : '0');
269            $objWriter->endElement();
270        }
271
272        // Italic
273        if ($pFont->getItalic() !== null) {
274            $objWriter->startElement('i');
275            $objWriter->writeAttribute('val', $pFont->getItalic() ? '1' : '0');
276            $objWriter->endElement();
277        }
278
279        // Strikethrough
280        if ($pFont->getStrikethrough() !== null) {
281            $objWriter->startElement('strike');
282            $objWriter->writeAttribute('val', $pFont->getStrikethrough() ? '1' : '0');
283            $objWriter->endElement();
284        }
285
286        // Underline
287        if ($pFont->getUnderline() !== null) {
288            $objWriter->startElement('u');
289            $objWriter->writeAttribute('val', $pFont->getUnderline());
290            $objWriter->endElement();
291        }
292
293        // Superscript / subscript
294        if ($pFont->getSuperscript() === true || $pFont->getSubscript() === true) {
295            $objWriter->startElement('vertAlign');
296            if ($pFont->getSuperscript() === true) {
297                $objWriter->writeAttribute('val', 'superscript');
298            } elseif ($pFont->getSubscript() === true) {
299                $objWriter->writeAttribute('val', 'subscript');
300            }
301            $objWriter->endElement();
302        }
303
304        // Size
305        if ($pFont->getSize() !== null) {
306            $objWriter->startElement('sz');
307            $objWriter->writeAttribute('val', StringHelper::formatNumber($pFont->getSize()));
308            $objWriter->endElement();
309        }
310
311        // Foreground color
312        if ($pFont->getColor()->getARGB() !== null) {
313            $objWriter->startElement('color');
314            $objWriter->writeAttribute('rgb', $pFont->getColor()->getARGB());
315            $objWriter->endElement();
316        }
317
318        // Name
319        if ($pFont->getName() !== null) {
320            $objWriter->startElement('name');
321            $objWriter->writeAttribute('val', $pFont->getName());
322            $objWriter->endElement();
323        }
324
325        $objWriter->endElement();
326    }
327
328    /**
329     * Write Border.
330     *
331     * @param XMLWriter $objWriter XML Writer
332     * @param Borders $pBorders Borders style
333     */
334    private function writeBorder(XMLWriter $objWriter, Borders $pBorders)
335    {
336        // Write border
337        $objWriter->startElement('border');
338        // Diagonal?
339        switch ($pBorders->getDiagonalDirection()) {
340            case Borders::DIAGONAL_UP:
341                $objWriter->writeAttribute('diagonalUp', 'true');
342                $objWriter->writeAttribute('diagonalDown', 'false');
343
344                break;
345            case Borders::DIAGONAL_DOWN:
346                $objWriter->writeAttribute('diagonalUp', 'false');
347                $objWriter->writeAttribute('diagonalDown', 'true');
348
349                break;
350            case Borders::DIAGONAL_BOTH:
351                $objWriter->writeAttribute('diagonalUp', 'true');
352                $objWriter->writeAttribute('diagonalDown', 'true');
353
354                break;
355        }
356
357        // BorderPr
358        $this->writeBorderPr($objWriter, 'left', $pBorders->getLeft());
359        $this->writeBorderPr($objWriter, 'right', $pBorders->getRight());
360        $this->writeBorderPr($objWriter, 'top', $pBorders->getTop());
361        $this->writeBorderPr($objWriter, 'bottom', $pBorders->getBottom());
362        $this->writeBorderPr($objWriter, 'diagonal', $pBorders->getDiagonal());
363        $objWriter->endElement();
364    }
365
366    /**
367     * Write Cell Style Xf.
368     *
369     * @param XMLWriter $objWriter XML Writer
370     * @param \PhpOffice\PhpSpreadsheet\Style\Style $pStyle Style
371     * @param Spreadsheet $spreadsheet Workbook
372     *
373     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
374     */
375    private function writeCellStyleXf(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Style\Style $pStyle, Spreadsheet $spreadsheet)
376    {
377        // xf
378        $objWriter->startElement('xf');
379        $objWriter->writeAttribute('xfId', 0);
380        $objWriter->writeAttribute('fontId', (int) $this->getParentWriter()->getFontHashTable()->getIndexForHashCode($pStyle->getFont()->getHashCode()));
381        if ($pStyle->getQuotePrefix()) {
382            $objWriter->writeAttribute('quotePrefix', 1);
383        }
384
385        if ($pStyle->getNumberFormat()->getBuiltInFormatCode() === false) {
386            $objWriter->writeAttribute('numFmtId', (int) ($this->getParentWriter()->getNumFmtHashTable()->getIndexForHashCode($pStyle->getNumberFormat()->getHashCode()) + 164));
387        } else {
388            $objWriter->writeAttribute('numFmtId', (int) $pStyle->getNumberFormat()->getBuiltInFormatCode());
389        }
390
391        $objWriter->writeAttribute('fillId', (int) $this->getParentWriter()->getFillHashTable()->getIndexForHashCode($pStyle->getFill()->getHashCode()));
392        $objWriter->writeAttribute('borderId', (int) $this->getParentWriter()->getBordersHashTable()->getIndexForHashCode($pStyle->getBorders()->getHashCode()));
393
394        // Apply styles?
395        $objWriter->writeAttribute('applyFont', ($spreadsheet->getDefaultStyle()->getFont()->getHashCode() != $pStyle->getFont()->getHashCode()) ? '1' : '0');
396        $objWriter->writeAttribute('applyNumberFormat', ($spreadsheet->getDefaultStyle()->getNumberFormat()->getHashCode() != $pStyle->getNumberFormat()->getHashCode()) ? '1' : '0');
397        $objWriter->writeAttribute('applyFill', ($spreadsheet->getDefaultStyle()->getFill()->getHashCode() != $pStyle->getFill()->getHashCode()) ? '1' : '0');
398        $objWriter->writeAttribute('applyBorder', ($spreadsheet->getDefaultStyle()->getBorders()->getHashCode() != $pStyle->getBorders()->getHashCode()) ? '1' : '0');
399        $objWriter->writeAttribute('applyAlignment', ($spreadsheet->getDefaultStyle()->getAlignment()->getHashCode() != $pStyle->getAlignment()->getHashCode()) ? '1' : '0');
400        if ($pStyle->getProtection()->getLocked() != Protection::PROTECTION_INHERIT || $pStyle->getProtection()->getHidden() != Protection::PROTECTION_INHERIT) {
401            $objWriter->writeAttribute('applyProtection', 'true');
402        }
403
404        // alignment
405        $objWriter->startElement('alignment');
406        $objWriter->writeAttribute('horizontal', $pStyle->getAlignment()->getHorizontal());
407        $objWriter->writeAttribute('vertical', $pStyle->getAlignment()->getVertical());
408
409        $textRotation = 0;
410        if ($pStyle->getAlignment()->getTextRotation() >= 0) {
411            $textRotation = $pStyle->getAlignment()->getTextRotation();
412        } elseif ($pStyle->getAlignment()->getTextRotation() < 0) {
413            $textRotation = 90 - $pStyle->getAlignment()->getTextRotation();
414        }
415        $objWriter->writeAttribute('textRotation', $textRotation);
416
417        $objWriter->writeAttribute('wrapText', ($pStyle->getAlignment()->getWrapText() ? 'true' : 'false'));
418        $objWriter->writeAttribute('shrinkToFit', ($pStyle->getAlignment()->getShrinkToFit() ? 'true' : 'false'));
419
420        if ($pStyle->getAlignment()->getIndent() > 0) {
421            $objWriter->writeAttribute('indent', $pStyle->getAlignment()->getIndent());
422        }
423        if ($pStyle->getAlignment()->getReadOrder() > 0) {
424            $objWriter->writeAttribute('readingOrder', $pStyle->getAlignment()->getReadOrder());
425        }
426        $objWriter->endElement();
427
428        // protection
429        if ($pStyle->getProtection()->getLocked() != Protection::PROTECTION_INHERIT || $pStyle->getProtection()->getHidden() != Protection::PROTECTION_INHERIT) {
430            $objWriter->startElement('protection');
431            if ($pStyle->getProtection()->getLocked() != Protection::PROTECTION_INHERIT) {
432                $objWriter->writeAttribute('locked', ($pStyle->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED ? 'true' : 'false'));
433            }
434            if ($pStyle->getProtection()->getHidden() != Protection::PROTECTION_INHERIT) {
435                $objWriter->writeAttribute('hidden', ($pStyle->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED ? 'true' : 'false'));
436            }
437            $objWriter->endElement();
438        }
439
440        $objWriter->endElement();
441    }
442
443    /**
444     * Write Cell Style Dxf.
445     *
446     * @param XMLWriter $objWriter XML Writer
447     * @param \PhpOffice\PhpSpreadsheet\Style\Style $pStyle Style
448     */
449    private function writeCellStyleDxf(XMLWriter $objWriter, \PhpOffice\PhpSpreadsheet\Style\Style $pStyle)
450    {
451        // dxf
452        $objWriter->startElement('dxf');
453
454        // font
455        $this->writeFont($objWriter, $pStyle->getFont());
456
457        // numFmt
458        $this->writeNumFmt($objWriter, $pStyle->getNumberFormat());
459
460        // fill
461        $this->writeFill($objWriter, $pStyle->getFill());
462
463        // alignment
464        $objWriter->startElement('alignment');
465        if ($pStyle->getAlignment()->getHorizontal() !== null) {
466            $objWriter->writeAttribute('horizontal', $pStyle->getAlignment()->getHorizontal());
467        }
468        if ($pStyle->getAlignment()->getVertical() !== null) {
469            $objWriter->writeAttribute('vertical', $pStyle->getAlignment()->getVertical());
470        }
471
472        if ($pStyle->getAlignment()->getTextRotation() !== null) {
473            $textRotation = 0;
474            if ($pStyle->getAlignment()->getTextRotation() >= 0) {
475                $textRotation = $pStyle->getAlignment()->getTextRotation();
476            } elseif ($pStyle->getAlignment()->getTextRotation() < 0) {
477                $textRotation = 90 - $pStyle->getAlignment()->getTextRotation();
478            }
479            $objWriter->writeAttribute('textRotation', $textRotation);
480        }
481        $objWriter->endElement();
482
483        // border
484        $this->writeBorder($objWriter, $pStyle->getBorders());
485
486        // protection
487        if (($pStyle->getProtection()->getLocked() !== null) || ($pStyle->getProtection()->getHidden() !== null)) {
488            if ($pStyle->getProtection()->getLocked() !== Protection::PROTECTION_INHERIT ||
489                $pStyle->getProtection()->getHidden() !== Protection::PROTECTION_INHERIT) {
490                $objWriter->startElement('protection');
491                if (($pStyle->getProtection()->getLocked() !== null) &&
492                    ($pStyle->getProtection()->getLocked() !== Protection::PROTECTION_INHERIT)) {
493                    $objWriter->writeAttribute('locked', ($pStyle->getProtection()->getLocked() == Protection::PROTECTION_PROTECTED ? 'true' : 'false'));
494                }
495                if (($pStyle->getProtection()->getHidden() !== null) &&
496                    ($pStyle->getProtection()->getHidden() !== Protection::PROTECTION_INHERIT)) {
497                    $objWriter->writeAttribute('hidden', ($pStyle->getProtection()->getHidden() == Protection::PROTECTION_PROTECTED ? 'true' : 'false'));
498                }
499                $objWriter->endElement();
500            }
501        }
502
503        $objWriter->endElement();
504    }
505
506    /**
507     * Write BorderPr.
508     *
509     * @param XMLWriter $objWriter XML Writer
510     * @param string $pName Element name
511     * @param Border $pBorder Border style
512     */
513    private function writeBorderPr(XMLWriter $objWriter, $pName, Border $pBorder)
514    {
515        // Write BorderPr
516        if ($pBorder->getBorderStyle() != Border::BORDER_NONE) {
517            $objWriter->startElement($pName);
518            $objWriter->writeAttribute('style', $pBorder->getBorderStyle());
519
520            // color
521            $objWriter->startElement('color');
522            $objWriter->writeAttribute('rgb', $pBorder->getColor()->getARGB());
523            $objWriter->endElement();
524
525            $objWriter->endElement();
526        }
527    }
528
529    /**
530     * Write NumberFormat.
531     *
532     * @param XMLWriter $objWriter XML Writer
533     * @param NumberFormat $pNumberFormat Number Format
534     * @param int $pId Number Format identifier
535     */
536    private function writeNumFmt(XMLWriter $objWriter, NumberFormat $pNumberFormat, $pId = 0)
537    {
538        // Translate formatcode
539        $formatCode = $pNumberFormat->getFormatCode();
540
541        // numFmt
542        if ($formatCode !== null) {
543            $objWriter->startElement('numFmt');
544            $objWriter->writeAttribute('numFmtId', ($pId + 164));
545            $objWriter->writeAttribute('formatCode', $formatCode);
546            $objWriter->endElement();
547        }
548    }
549
550    /**
551     * Get an array of all styles.
552     *
553     * @param Spreadsheet $spreadsheet
554     *
555     * @return \PhpOffice\PhpSpreadsheet\Style\Style[] All styles in PhpSpreadsheet
556     */
557    public function allStyles(Spreadsheet $spreadsheet)
558    {
559        return $spreadsheet->getCellXfCollection();
560    }
561
562    /**
563     * Get an array of all conditional styles.
564     *
565     * @param Spreadsheet $spreadsheet
566     *
567     * @return Conditional[] All conditional styles in PhpSpreadsheet
568     */
569    public function allConditionalStyles(Spreadsheet $spreadsheet)
570    {
571        // Get an array of all styles
572        $aStyles = [];
573
574        $sheetCount = $spreadsheet->getSheetCount();
575        for ($i = 0; $i < $sheetCount; ++$i) {
576            foreach ($spreadsheet->getSheet($i)->getConditionalStylesCollection() as $conditionalStyles) {
577                foreach ($conditionalStyles as $conditionalStyle) {
578                    $aStyles[] = $conditionalStyle;
579                }
580            }
581        }
582
583        return $aStyles;
584    }
585
586    /**
587     * Get an array of all fills.
588     *
589     * @param Spreadsheet $spreadsheet
590     *
591     * @return Fill[] All fills in PhpSpreadsheet
592     */
593    public function allFills(Spreadsheet $spreadsheet)
594    {
595        // Get an array of unique fills
596        $aFills = [];
597
598        // Two first fills are predefined
599        $fill0 = new Fill();
600        $fill0->setFillType(Fill::FILL_NONE);
601        $aFills[] = $fill0;
602
603        $fill1 = new Fill();
604        $fill1->setFillType(Fill::FILL_PATTERN_GRAY125);
605        $aFills[] = $fill1;
606        // The remaining fills
607        $aStyles = $this->allStyles($spreadsheet);
608        /** @var \PhpOffice\PhpSpreadsheet\Style\Style $style */
609        foreach ($aStyles as $style) {
610            if (!isset($aFills[$style->getFill()->getHashCode()])) {
611                $aFills[$style->getFill()->getHashCode()] = $style->getFill();
612            }
613        }
614
615        return $aFills;
616    }
617
618    /**
619     * Get an array of all fonts.
620     *
621     * @param Spreadsheet $spreadsheet
622     *
623     * @return Font[] All fonts in PhpSpreadsheet
624     */
625    public function allFonts(Spreadsheet $spreadsheet)
626    {
627        // Get an array of unique fonts
628        $aFonts = [];
629        $aStyles = $this->allStyles($spreadsheet);
630
631        /** @var \PhpOffice\PhpSpreadsheet\Style\Style $style */
632        foreach ($aStyles as $style) {
633            if (!isset($aFonts[$style->getFont()->getHashCode()])) {
634                $aFonts[$style->getFont()->getHashCode()] = $style->getFont();
635            }
636        }
637
638        return $aFonts;
639    }
640
641    /**
642     * Get an array of all borders.
643     *
644     * @param Spreadsheet $spreadsheet
645     *
646     * @return Borders[] All borders in PhpSpreadsheet
647     */
648    public function allBorders(Spreadsheet $spreadsheet)
649    {
650        // Get an array of unique borders
651        $aBorders = [];
652        $aStyles = $this->allStyles($spreadsheet);
653
654        /** @var \PhpOffice\PhpSpreadsheet\Style\Style $style */
655        foreach ($aStyles as $style) {
656            if (!isset($aBorders[$style->getBorders()->getHashCode()])) {
657                $aBorders[$style->getBorders()->getHashCode()] = $style->getBorders();
658            }
659        }
660
661        return $aBorders;
662    }
663
664    /**
665     * Get an array of all number formats.
666     *
667     * @param Spreadsheet $spreadsheet
668     *
669     * @return NumberFormat[] All number formats in PhpSpreadsheet
670     */
671    public function allNumberFormats(Spreadsheet $spreadsheet)
672    {
673        // Get an array of unique number formats
674        $aNumFmts = [];
675        $aStyles = $this->allStyles($spreadsheet);
676
677        /** @var \PhpOffice\PhpSpreadsheet\Style\Style $style */
678        foreach ($aStyles as $style) {
679            if ($style->getNumberFormat()->getBuiltInFormatCode() === false && !isset($aNumFmts[$style->getNumberFormat()->getHashCode()])) {
680                $aNumFmts[$style->getNumberFormat()->getHashCode()] = $style->getNumberFormat();
681            }
682        }
683
684        return $aNumFmts;
685    }
686}
687