Passed
Pull Request — develop_3.0 (#488)
by Adrien
02:35
created

StyleManager   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 237
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 28
lcom 1
cbo 6
dl 0
loc 237
ccs 89
cts 89
cp 1
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A shouldApplyStyleOnEmptyCell() 0 10 4
A getStylesXMLFileContent() 0 20 1
B getFontsSectionContent() 0 34 6
B getFillsSectionContent() 0 27 2
B getBordersSectionContent() 0 36 4
A getCellStyleXfsSectionContent() 0 8 1
D getCellXfsSectionContent() 0 36 9
A getCellStylesSectionContent() 0 8 1
1
<?php
2
3
namespace Box\Spout\Writer\XLSX\Manager\Style;
4
5
use Box\Spout\Writer\Common\Entity\Style\Color;
6
use Box\Spout\Writer\Common\Entity\Style\Style;
7
use Box\Spout\Writer\XLSX\Helper\BorderHelper;
8
9
/**
10
 * Class StyleManager
11
 * Manages styles to be applied to a cell
12
 */
13
class StyleManager extends \Box\Spout\Writer\Common\Manager\Style\StyleManager
14
{
15
    /** @var StyleRegistry */
16
    protected $styleRegistry;
17
18
    /**
19
     * For empty cells, we can specify a style or not. If no style are specified,
20
     * then the software default will be applied. But sometimes, it may be useful
21
     * to override this default style, for instance if the cell should have a
22
     * background color different than the default one or some borders
23
     * (fonts property don't really matter here).
24
     *
25
     * @param int $styleId
26
     * @return bool Whether the cell should define a custom style
27
     */
28 11
    public function shouldApplyStyleOnEmptyCell($styleId)
29
    {
30 11
        $associatedFillId = $this->styleRegistry->getFillIdForStyleId($styleId);
31 11
        $hasStyleCustomFill = ($associatedFillId !== null && $associatedFillId !== 0);
32
33 11
        $associatedBorderId = $this->styleRegistry->getBorderIdForStyleId($styleId);
34 11
        $hasStyleCustomBorders = ($associatedBorderId !== null && $associatedBorderId !== 0);
35
36 11
        return ($hasStyleCustomFill || $hasStyleCustomBorders);
37
    }
38
39
    /**
40
     * Returns the content of the "styles.xml" file, given a list of styles.
41
     *
42
     * @return string
43
     */
44 34
    public function getStylesXMLFileContent()
45
    {
46
        $content = <<<'EOD'
47 34
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
48
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
49
EOD;
50
51 34
        $content .= $this->getFontsSectionContent();
52 34
        $content .= $this->getFillsSectionContent();
53 34
        $content .= $this->getBordersSectionContent();
54 34
        $content .= $this->getCellStyleXfsSectionContent();
55 34
        $content .= $this->getCellXfsSectionContent();
56 34
        $content .= $this->getCellStylesSectionContent();
57
58
        $content .= <<<'EOD'
59 34
</styleSheet>
60
EOD;
61
62 34
        return $content;
63
    }
64
65
    /**
66
     * Returns the content of the "<fonts>" section.
67
     *
68
     * @return string
69
     */
70 34
    protected function getFontsSectionContent()
71
    {
72 34
        $registeredStyles = $this->styleRegistry->getRegisteredStyles();
73
74 34
        $content = '<fonts count="' . count($registeredStyles) . '">';
75
76
        /** @var Style $style */
77 34
        foreach ($registeredStyles as $style) {
78 34
            $content .= '<font>';
79
80 34
            $content .= '<sz val="' . $style->getFontSize() . '"/>';
81 34
            $content .= '<color rgb="' . Color::toARGB($style->getFontColor()) . '"/>';
82 34
            $content .= '<name val="' . $style->getFontName() . '"/>';
83
84 34
            if ($style->isFontBold()) {
85 6
                $content .= '<b/>';
86
            }
87 34
            if ($style->isFontItalic()) {
88 1
                $content .= '<i/>';
89
            }
90 34
            if ($style->isFontUnderline()) {
91 1
                $content .= '<u/>';
92
            }
93 34
            if ($style->isFontStrikethrough()) {
94 1
                $content .= '<strike/>';
95
            }
96
97 34
            $content .= '</font>';
98
        }
99
100 34
        $content .= '</fonts>';
101
102 34
        return $content;
103
    }
104
105
    /**
106
     * Returns the content of the "<fills>" section.
107
     *
108
     * @return string
109
     */
110 34
    protected function getFillsSectionContent()
111
    {
112 34
        $registeredFills = $this->styleRegistry->getRegisteredFills();
113
114
        // Excel reserves two default fills
115 34
        $fillsCount = count($registeredFills) + 2;
116 34
        $content = sprintf('<fills count="%d">', $fillsCount);
117
118 34
        $content .= '<fill><patternFill patternType="none"/></fill>';
119 34
        $content .= '<fill><patternFill patternType="gray125"/></fill>';
120
121
        // The other fills are actually registered by setting a background color
122 34
        foreach ($registeredFills as $styleId) {
123
            /** @var Style $style */
124 3
            $style = $this->styleRegistry->getStyleFromStyleId($styleId);
125
126 3
            $backgroundColor = $style->getBackgroundColor();
127 3
            $content .= sprintf(
128 3
                '<fill><patternFill patternType="solid"><fgColor rgb="%s"/></patternFill></fill>',
129 3
                $backgroundColor
130
            );
131
        }
132
133 34
        $content .= '</fills>';
134
135 34
        return $content;
136
    }
137
138
    /**
139
     * Returns the content of the "<borders>" section.
140
     *
141
     * @return string
142
     */
143 34
    protected function getBordersSectionContent()
144
    {
145 34
        $registeredBorders = $this->styleRegistry->getRegisteredBorders();
146
147
        // There is one default border with index 0
148 34
        $borderCount = count($registeredBorders) + 1;
149
150 34
        $content = '<borders count="' . $borderCount . '">';
151
152
        // Default border starting at index 0
153 34
        $content .= '<border><left/><right/><top/><bottom/></border>';
154
155 34
        foreach ($registeredBorders as $styleId) {
156
            /** @var \Box\Spout\Writer\Common\Entity\Style\Style $style */
157 4
            $style = $this->styleRegistry->getStyleFromStyleId($styleId);
158 4
            $border = $style->getBorder();
159 4
            $content .= '<border>';
160
161
            // @link https://github.com/box/spout/issues/271
162 4
            $sortOrder = ['left', 'right', 'top', 'bottom'];
163
164 4
            foreach ($sortOrder as $partName) {
165 4
                if ($border->hasPart($partName)) {
166
                    /** @var $part \Box\Spout\Writer\Common\Entity\Style\BorderPart */
167 4
                    $part = $border->getPart($partName);
168 4
                    $content .= BorderHelper::serializeBorderPart($part);
169
                }
170
            }
171
172 4
            $content .= '</border>';
173
        }
174
175 34
        $content .= '</borders>';
176
177 34
        return $content;
178
    }
179
180
    /**
181
     * Returns the content of the "<cellStyleXfs>" section.
182
     *
183
     * @return string
184
     */
185 34
    protected function getCellStyleXfsSectionContent()
186
    {
187
        return <<<'EOD'
188 34
<cellStyleXfs count="1">
189
    <xf borderId="0" fillId="0" fontId="0" numFmtId="0"/>
190
</cellStyleXfs>
191
EOD;
192
    }
193
194
    /**
195
     * Returns the content of the "<cellXfs>" section.
196
     *
197
     * @return string
198
     */
199 34
    protected function getCellXfsSectionContent()
200
    {
201 34
        $registeredStyles = $this->styleRegistry->getRegisteredStyles();
202
203 34
        $content = '<cellXfs count="' . count($registeredStyles) . '">';
204
205 34
        foreach ($registeredStyles as $style) {
206 34
            $styleId = $style->getId();
207 34
            $isDefaultStyle = ($styleId === 0);
208
209
            // For the default style (ID = 0), we don't want to override the fill nor the border.
210
            // Otherwise all cells of the spreadsheet will have a background color/border.
211 34
            $fillId = $isDefaultStyle ? 0 : ($this->styleRegistry->getFillIdForStyleId($styleId) ?: 0);
212 34
            $borderId = $isDefaultStyle ? 0 : ($this->styleRegistry->getBorderIdForStyleId($styleId) ?: 0);
213
214 34
            $content .= '<xf numFmtId="0" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"';
215
216 34
            if ($style->shouldApplyFont()) {
217 34
                $content .= ' applyFont="1"';
218
            }
219
220 34
            $content .= sprintf(' applyBorder="%d"', $style->shouldApplyBorder() ? 1 : 0);
221
222 34
            if ($style->shouldWrapText()) {
223 2
                $content .= ' applyAlignment="1">';
224 2
                $content .= '<alignment wrapText="1"/>';
225 2
                $content .= '</xf>';
226
            } else {
227 34
                $content .= '/>';
228
            }
229
        }
230
231 34
        $content .= '</cellXfs>';
232
233 34
        return $content;
234
    }
235
236
    /**
237
     * Returns the content of the "<cellStyles>" section.
238
     *
239
     * @return string
240
     */
241 34
    protected function getCellStylesSectionContent()
242
    {
243
        return <<<'EOD'
244 34
<cellStyles count="1">
245
    <cellStyle builtinId="0" name="Normal" xfId="0"/>
246
</cellStyles>
247
EOD;
248
    }
249
}
250