Completed
Pull Request — master (#557)
by Adrien
03:10
created

StyleManager::getCellStyleXfsSectionContent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 2
cts 2
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Box\Spout\Writer\XLSX\Manager\Style;
4
5
use Box\Spout\Common\Entity\Style\Color;
6
use Box\Spout\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 36
    public function getStylesXMLFileContent()
45
    {
46
        $content = <<<'EOD'
47 36
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
48
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
49
EOD;
50
51 36
        $content .= $this->getFontsSectionContent();
52 36
        $content .= $this->getFillsSectionContent();
53 36
        $content .= $this->getBordersSectionContent();
54 36
        $content .= $this->getCellStyleXfsSectionContent();
55 36
        $content .= $this->getCellXfsSectionContent();
56 36
        $content .= $this->getCellStylesSectionContent();
57
58
        $content .= <<<'EOD'
59 36
</styleSheet>
60
EOD;
61
62 36
        return $content;
63
    }
64
65
    /**
66
     * Returns the content of the "<fonts>" section.
67
     *
68
     * @return string
69
     */
70 36
    protected function getFontsSectionContent()
71
    {
72 36
        $registeredStyles = $this->styleRegistry->getRegisteredStyles();
73
74 36
        $content = '<fonts count="' . count($registeredStyles) . '">';
75
76
        /** @var Style $style */
77 36
        foreach ($registeredStyles as $style) {
78 36
            $content .= '<font>';
79
80 36
            $content .= '<sz val="' . $style->getFontSize() . '"/>';
81 36
            $content .= '<color rgb="' . Color::toARGB($style->getFontColor()) . '"/>';
82 36
            $content .= '<name val="' . $style->getFontName() . '"/>';
83
84 36
            if ($style->isFontBold()) {
85 7
                $content .= '<b/>';
86
            }
87 36
            if ($style->isFontItalic()) {
88 1
                $content .= '<i/>';
89
            }
90 36
            if ($style->isFontUnderline()) {
91 2
                $content .= '<u/>';
92
            }
93 36
            if ($style->isFontStrikethrough()) {
94 1
                $content .= '<strike/>';
95
            }
96
97 36
            $content .= '</font>';
98
        }
99
100 36
        $content .= '</fonts>';
101
102 36
        return $content;
103
    }
104
105
    /**
106
     * Returns the content of the "<fills>" section.
107
     *
108
     * @return string
109
     */
110 36
    protected function getFillsSectionContent()
111
    {
112 36
        $registeredFills = $this->styleRegistry->getRegisteredFills();
113
114
        // Excel reserves two default fills
115 36
        $fillsCount = count($registeredFills) + 2;
116 36
        $content = sprintf('<fills count="%d">', $fillsCount);
117
118 36
        $content .= '<fill><patternFill patternType="none"/></fill>';
119 36
        $content .= '<fill><patternFill patternType="gray125"/></fill>';
120
121
        // The other fills are actually registered by setting a background color
122 36
        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 36
        $content .= '</fills>';
134
135 36
        return $content;
136
    }
137
138
    /**
139
     * Returns the content of the "<borders>" section.
140
     *
141
     * @return string
142
     */
143 36
    protected function getBordersSectionContent()
144
    {
145 36
        $registeredBorders = $this->styleRegistry->getRegisteredBorders();
146
147
        // There is one default border with index 0
148 36
        $borderCount = count($registeredBorders) + 1;
149
150 36
        $content = '<borders count="' . $borderCount . '">';
151
152
        // Default border starting at index 0
153 36
        $content .= '<border><left/><right/><top/><bottom/></border>';
154
155 36
        foreach ($registeredBorders as $styleId) {
156
            /** @var \Box\Spout\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\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 36
        $content .= '</borders>';
176
177 36
        return $content;
178
    }
179
180
    /**
181
     * Returns the content of the "<cellStyleXfs>" section.
182
     *
183
     * @return string
184
     */
185 36
    protected function getCellStyleXfsSectionContent()
186
    {
187
        return <<<'EOD'
188 36
<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 36
    protected function getCellXfsSectionContent()
200
    {
201 36
        $registeredStyles = $this->styleRegistry->getRegisteredStyles();
202
203 36
        $content = '<cellXfs count="' . count($registeredStyles) . '">';
204
205 36
        foreach ($registeredStyles as $style) {
206 36
            $styleId = $style->getId();
207 36
            $fillId = $this->getFillIdForStyleId($styleId);
208 36
            $borderId = $this->getBorderIdForStyleId($styleId);
209
210 36
            $content .= '<xf numFmtId="0" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $borderId . '" xfId="0"';
211
212 36
            if ($style->shouldApplyFont()) {
213 36
                $content .= ' applyFont="1"';
214
            }
215
216 36
            $content .= sprintf(' applyBorder="%d"', $style->shouldApplyBorder() ? 1 : 0);
217
218 36
            if ($style->shouldWrapText()) {
219 2
                $content .= ' applyAlignment="1">';
220 2
                $content .= '<alignment wrapText="1"/>';
221 2
                $content .= '</xf>';
222
            } else {
223 36
                $content .= '/>';
224
            }
225
        }
226
227 36
        $content .= '</cellXfs>';
228
229 36
        return $content;
230
    }
231
232
    /**
233
     * Returns the fill ID associated to the given style ID.
234
     * For the default style, we don't a fill.
235
     *
236
     * @param int $styleId
237
     * @return int
238
     */
239 36
    private function getFillIdForStyleId($styleId)
240
    {
241
        // For the default style (ID = 0), we don't want to override the fill.
242
        // Otherwise all cells of the spreadsheet will have a background color.
243 36
        $isDefaultStyle = ($styleId === 0);
244
245 36
        return $isDefaultStyle ? 0 : ($this->styleRegistry->getFillIdForStyleId($styleId) ?: 0);
246
    }
247
248
    /**
249
     * Returns the fill ID associated to the given style ID.
250
     * For the default style, we don't a border.
251
     *
252
     * @param int $styleId
253
     * @return int
254
     */
255 36
    private function getBorderIdForStyleId($styleId)
256
    {
257
        // For the default style (ID = 0), we don't want to override the border.
258
        // Otherwise all cells of the spreadsheet will have a border.
259 36
        $isDefaultStyle = ($styleId === 0);
260
261 36
        return $isDefaultStyle ? 0 : ($this->styleRegistry->getBorderIdForStyleId($styleId) ?: 0);
262
    }
263
264
    /**
265
     * Returns the content of the "<cellStyles>" section.
266
     *
267
     * @return string
268
     */
269 36
    protected function getCellStylesSectionContent()
270
    {
271
        return <<<'EOD'
272 36
<cellStyles count="1">
273
    <cellStyle builtinId="0" name="Normal" xfId="0"/>
274
</cellStyles>
275
EOD;
276
    }
277
}
278