Completed
Pull Request — master (#211)
by Hura
14:55
created

StyleHelper::getFillsSectionContent()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2

Importance

Changes 4
Bugs 0 Features 2
Metric Value
c 4
b 0
f 2
dl 0
loc 26
ccs 10
cts 10
cp 1
rs 8.8571
cc 2
eloc 13
nc 2
nop 0
crap 2
1
<?php
2
3
namespace Box\Spout\Writer\XLSX\Helper;
4
5
use Box\Spout\Writer\Common\Helper\AbstractStyleHelper;
6
use Box\Spout\Writer\Style\Color;
7
use Box\Spout\Writer\Style\Style;
8
9
/**
10
 * Class StyleHelper
11
 * This class provides helper functions to manage styles
12
 *
13
 * @package Box\Spout\Writer\XLSX\Helper
14
 */
15
class StyleHelper extends AbstractStyleHelper
16
{
17
    /**
18
     * @var array
19
     */
20
    protected $registeredFills = [];
21 72
22
    /**
23
     * @var array [STYLE_ID] => [FILL_ID] maps a style to a fill declaration
24
     */
25
    protected $styleIdToFillMappingTable = [];
26 72
27
    /**
28 72
     * Excel preserves two default fills with index 0 and 1
29 72
     * Since Excel is the dominant vendor - we play along here
30 72
     *
31 72
     * @var int The fill index counter for custom fills.
32 72
     */
33 72
    protected $fillIndex = 2;
34
35
    /**
36
     * XLSX specific operations on the registered styles
37 72
     *
38
     * @param \Box\Spout\Writer\Style\Style $style
39 72
     * @return \Box\Spout\Writer\Style\Style
40
     */
41
    public function registerStyle($style)
42
    {
43
        $registeredStyle = parent::registerStyle($style);
44
        $this->registerFill($registeredStyle);
45
        return $registeredStyle;
46
    }
47 72
48
    /**
49 72
     * Register a fill definition
50
     *
51
     * @param \Box\Spout\Writer\Style\Style $style
52 72
     */
53 72
    protected function registerFill($style)
54
    {
55 72
        $styleId = $style->getId();
56 72
57 72
        // Currently - only solid backgrounds are supported
58
        // so $backgroundColor is a scalar value (RGB Color)
59 72
        $backgroundColor = $style->getBackgroundColor();
60 9
61 9
        // We need to track the already registered background definitions
62 72
        if (isset($backgroundColor) && !isset($this->registeredFills[$backgroundColor])) {
63 3
            $this->registeredFills[$backgroundColor] = $styleId;
64 3
        }
65 72
66 3
        if (!isset($this->styleIdToFillMappingTable[$styleId])) {
67 3
            // The fillId maps a style to a fill declaration
68 72
            // When there is no background color definition - we default to 0
69 3
            $fillId = $backgroundColor !== null ? $this->fillIndex++ : 0;
70 3
            $this->styleIdToFillMappingTable[$styleId] = $fillId;
71
        }
72 72
    }
73 72
74
75 72
    /**
76
     * Returns the content of the "styles.xml" file, given a list of styles.
77 72
     *
78
     * @return string
79
     */
80
    public function getStylesXMLFileContent()
81
    {
82
        $content = <<<EOD
83
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
84
<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
85 72
EOD;
86
87
        $content .= $this->getFontsSectionContent();
88
        $content .= $this->getFillsSectionContent();
89
        $content .= $this->getBordersSectionContent();
90
        $content .= $this->getCellStyleXfsSectionContent();
91
        $content .= $this->getCellXfsSectionContent();
92
        $content .= $this->getCellStylesSectionContent();
93 72
94
        $content .= <<<EOD
95
</styleSheet>
96
EOD;
97
98
        return $content;
99
    }
100
101 72
    /**
102
     * Returns the content of the "<fonts>" section.
103 72
     *
104 72
     * @return string
105
     */
106 72
    protected function getFontsSectionContent()
107
    {
108
        $content = '<fonts count="' . count($this->styleIdToStyleMappingTable) . '">';
109 72
110 72
        /** @var \Box\Spout\Writer\Style\Style $style */
111 72
        foreach ($this->getRegisteredStyles() as $style) {
112 6
            $content .= '<font>';
113
114
            $content .= '<sz val="' . $style->getFontSize() . '"/>';
115 6
            $content .= '<color rgb="' . Color::toARGB($style->getFontColor()) . '"/>';
116
            $content .= '<name val="' . $style->getFontName() . '"/>';
117 6
118 6
            if ($style->isFontBold()) {
119
                $content .= '<b/>';
120 6
            }
121 6
            if ($style->isFontItalic()) {
122 6
                $content .= '<i/>';
123 6
            }
124
            if ($style->isFontUnderline()) {
125 6
                $content .= '<u/>';
126
            }
127 6
            if ($style->isFontStrikethrough()) {
128 72
                $content .= '<strike/>';
129
            }
130 72
131
            $content .= '</font>';
132 72
        }
133
134 72
        $content .= '</fonts>';
135
136
        return $content;
137
    }
138
139
    /**
140
     * Returns the content of the "<fills>" section.
141
     *
142 72
     * @return string
143
     */
144
    protected function getFillsSectionContent()
145
    {
146
        // Excel reserves two default fills
147
        $fillsCount = count($this->registeredFills) + 2;
148 72
        $content = sprintf('<fills count="%d">', $fillsCount);
149
150
        $content .= '<fill><patternFill patternType="none"/></fill>';
151
        $content .= '<fill><patternFill patternType="gray125"/></fill>';
152
153
        // The other fills are actually registered by setting a background color
154
        foreach ($this->registeredFills as $styleId) {
155
156 72
            /** @var Style $style */
157
            $style = $this->styleIdToStyleMappingTable[$styleId];
158 72
159
            $backgroundColor = $style->getBackgroundColor();
160 72
            $content .= sprintf(
161
                '<fill><patternFill patternType="solid"><fgColor rgb="%s"/></patternFill></fill>',
162 72
                $backgroundColor
163 72
            );
164
        }
165 72
166 72
        $content .= '</fills>';
167 72
168
        return $content;
169 72
    }
170 6
171 6
    /**
172
     * Returns the content of the "<borders>" section.
173 72
     *
174 6
     * @return string
175 6
     */
176 6
    protected function getBordersSectionContent()
177 6
    {
178 72
        $registeredStyles = $this->getRegisteredStyles();
179
        $registeredStylesCount = count($registeredStyles);
180 72
181
        $content = '<borders count="' . $registeredStylesCount . '">';
182 72
183
        /** @var \Box\Spout\Writer\Style\Style $style */
184 72
        foreach ($registeredStyles as $style) {
185
            $border = $style->getBorder();
186
            if ($border) {
187
                $content .= '<border>';
188
189
                // @link https://github.com/box/spout/issues/271
190
                $sortOrder = ['left', 'right', 'top', 'bottom'];
191
192 72
                foreach ($sortOrder as $partName) {
193
                    if ($border->hasPart($partName)) {
194
                        /** @var $part \Box\Spout\Writer\Style\BorderPart */
195
                        $part = $border->getPart($partName);
196
                        $content .= BorderHelper::serializeBorderPart($part);
197
                    }
198 72
                }
199
200
                $content .= '</border>';
201
202
            } else {
203
                $content .= '<border><left/><right/><top/><bottom/></border>';
204
            }
205
        }
206
207
        $content .= '</borders>';
208
209
        return $content;
210
    }
211
212
    /**
213
     * Returns the content of the "<cellStyleXfs>" section.
214
     *
215
     * @return string
216
     */
217
    protected function getCellStyleXfsSectionContent()
218
    {
219
        return <<<EOD
220
<cellStyleXfs count="1">
221
    <xf borderId="0" fillId="0" fontId="0" numFmtId="0"/>
222
</cellStyleXfs>
223
EOD;
224
    }
225
226
    /**
227
     * Returns the content of the "<cellXfs>" section.
228
     *
229
     * @return string
230
     */
231
    protected function getCellXfsSectionContent()
232
    {
233
        $registeredStyles = $this->getRegisteredStyles();
234
235
        $content = '<cellXfs count="' . count($registeredStyles) . '">';
236
237
        foreach ($registeredStyles as $style) {
238
239
            $styleId = $style->getId();
240
            $fillId = $this->styleIdToFillMappingTable[$styleId];
241
242
            $content .= '<xf numFmtId="0" fontId="' . $styleId . '" fillId="' . $fillId . '" borderId="' . $styleId . '" xfId="0"';
243
244
            if ($style->shouldApplyFont()) {
245
                $content .= ' applyFont="1"';
246
            }
247
248
            if ($style->shouldApplyBorder()) {
249
                $content .= ' applyBorder="1"';
250
            }
251
252
            if ($style->shouldWrapText()) {
253
                $content .= ' applyAlignment="1">';
254
                $content .= '<alignment wrapText="1"/>';
255
                $content .= '</xf>';
256
            } else {
257
                $content .= '/>';
258
            }
259
        }
260
261
        $content .= '</cellXfs>';
262
263
        return $content;
264
    }
265
266
    /**
267
     * Returns the content of the "<cellStyles>" section.
268
     *
269
     * @return string
270
     */
271
    protected function getCellStylesSectionContent()
272
    {
273
        return <<<EOD
274
<cellStyles count="1">
275
    <cellStyle builtinId="0" name="Normal" xfId="0"/>
276
</cellStyles>
277
EOD;
278
    }
279
}
280