Completed
Push — master ( eb84ec...8c1f0c )
by Adrien
04:15
created

StyleRegistry   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 270
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 95.38%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 2
dl 0
loc 270
ccs 62
cts 65
cp 0.9538
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A registerStyle() 0 13 2
A registerFormat() 0 25 3
A getFormatIdForStyleId() 0 4 1
A registerFill() 0 26 3
A getFillIdForStyleId() 0 6 2
A registerBorder() 0 23 3
A getBorderIdForStyleId() 0 6 2
A getRegisteredFills() 0 4 1
A getRegisteredBorders() 0 4 1
A getRegisteredFormats() 0 4 1
1
<?php
2
3
namespace Box\Spout\Writer\XLSX\Manager\Style;
4
5
use Box\Spout\Common\Entity\Style\Style;
6
7
/**
8
 * Class StyleRegistry
9
 * Registry for all used styles
10
 */
11
class StyleRegistry extends \Box\Spout\Writer\Common\Manager\Style\StyleRegistry
12
{
13
    /**
14
     * @see https://msdn.microsoft.com/en-us/library/ff529597(v=office.12).aspx
15
     * @var array Mapping between built-in format and the associated numFmtId
16
     */
17
    protected static $builtinNumFormatToIdMapping = [
18
        'General' => 0,
19
        '0' => 1,
20
        '0.00' => 2,
21
        '#,##0' => 3,
22
        '#,##0.00' => 4,
23
        '$#,##0,\-$#,##0' => 5,
24
        '$#,##0,[Red]\-$#,##0' => 6,
25
        '$#,##0.00,\-$#,##0.00' => 7,
26
        '$#,##0.00,[Red]\-$#,##0.00' => 8,
27
        '0%' => 9,
28
        '0.00%' => 10,
29
        '0.00E+00' => 11,
30
        '# ?/?' => 12,
31
        '# ??/??' => 13,
32
        'mm-dd-yy' => 14,
33
        'd-mmm-yy' => 15,
34
        'd-mmm' => 16,
35
        'mmm-yy' => 17,
36
        'h:mm AM/PM' => 18,
37
        'h:mm:ss AM/PM' => 19,
38
        'h:mm' => 20,
39
        'h:mm:ss' => 21,
40
        'm/d/yy h:mm' => 22,
41
42
        '#,##0 ,(#,##0)' => 37,
43
        '#,##0 ,[Red](#,##0)' => 38,
44
        '#,##0.00,(#,##0.00)' => 39,
45
        '#,##0.00,[Red](#,##0.00)' => 40,
46
47
        '_("$"* #,##0.00_),_("$"* \(#,##0.00\),_("$"* "-"??_),_(@_)' => 44,
48
        'mm:ss' => 45,
49
        '[h]:mm:ss' => 46,
50
        'mm:ss.0' => 47,
51
52
        '##0.0E+0' => 48,
53
        '@' => 49,
54
55
        '[$-404]e/m/d' => 27,
56
        'm/d/yy' => 30,
57
        't0' => 59,
58
        't0.00' => 60,
59
        't#,##0' => 61,
60
        't#,##0.00' => 62,
61
        't0%' => 67,
62
        't0.00%' => 68,
63
        't# ?/?' => 69,
64
        't# ??/??' => 70,
65
    ];
66
67
    /**
68
     * @var array
69
     */
70
    protected $registeredFormats = [];
71
72
    /**
73
     * @var array [STYLE_ID] => [FORMAT_ID] maps a style to a format declaration
74
     */
75
    protected $styleIdToFormatsMappingTable = [];
76
77
    /**
78
     * If the numFmtId is lower than 0xA4 (164 in decimal)
79
     * then it's a built-in number format.
80
     * Since Excel is the dominant vendor - we play along here
81
     *
82
     * @var int The fill index counter for custom fills.
83
     */
84
    protected $formatIndex = 164;
85
86
    /**
87
     * @var array
88
     */
89
    protected $registeredFills = [];
90
91
    /**
92
     * @var array [STYLE_ID] => [FILL_ID] maps a style to a fill declaration
93
     */
94
    protected $styleIdToFillMappingTable = [];
95
96
    /**
97
     * Excel preserves two default fills with index 0 and 1
98
     * Since Excel is the dominant vendor - we play along here
99
     *
100
     * @var int The fill index counter for custom fills.
101
     */
102
    protected $fillIndex = 2;
103
104
    /**
105
     * @var array
106
     */
107
    protected $registeredBorders = [];
108
109
    /**
110
     * @var array [STYLE_ID] => [BORDER_ID] maps a style to a border declaration
111
     */
112
    protected $styleIdToBorderMappingTable = [];
113
114
    /**
115
     * XLSX specific operations on the registered styles
116
     *
117
     * @param Style $style
118
     * @return Style
119
     */
120 46
    public function registerStyle(Style $style)
121
    {
122 46
        if ($style->isRegistered()) {
123 18
            return $style;
124
        }
125
126 46
        $registeredStyle = parent::registerStyle($style);
127 46
        $this->registerFill($registeredStyle);
128 46
        $this->registerFormat($registeredStyle);
129 46
        $this->registerBorder($registeredStyle);
130
131 46
        return $registeredStyle;
132
    }
133
134
    /**
135
     * Register a format definition
136
     *
137
     * @param Style $style
138
     */
139 46
    protected function registerFormat(Style $style)
140
    {
141 46
        $styleId = $style->getId();
142
143 46
        $format = $style->getFormat();
144 46
        if ($format) {
145 2
            $isFormatRegistered = isset($this->registeredFormats[$format]);
146
147
            // We need to track the already registered format definitions
148 2
            if ($isFormatRegistered) {
149
                $registeredStyleId = $this->registeredFormats[$format];
150
                $registeredFormatId = $this->styleIdToFormatsMappingTable[$registeredStyleId];
151
                $this->styleIdToFormatsMappingTable[$styleId] = $registeredFormatId;
152
            } else {
153 2
                $this->registeredFormats[$format] = $styleId;
154
155 2
                $id = self::$builtinNumFormatToIdMapping[$format] ?? $this->formatIndex++;
156 2
                $this->styleIdToFormatsMappingTable[$styleId] = $id;
157
            }
158
        } else {
159
            // The formatId maps a style to a format declaration
160
            // When there is no format definition - we default to 0 ( General )
161 46
            $this->styleIdToFormatsMappingTable[$styleId] = 0;
162
        }
163 46
    }
164
165
    /**
166
     * @param int $styleId
167
     * @return int|null Format ID associated to the given style ID
168
     */
169 25
    public function getFormatIdForStyleId($styleId)
170
    {
171 25
        return $this->styleIdToFormatsMappingTable[$styleId] ?? null;
172
    }
173
174
    /**
175
     * Register a fill definition
176
     *
177
     * @param Style $style
178
     */
179 46
    private function registerFill(Style $style)
180
    {
181 46
        $styleId = $style->getId();
182
183
        // Currently - only solid backgrounds are supported
184
        // so $backgroundColor is a scalar value (RGB Color)
185 46
        $backgroundColor = $style->getBackgroundColor();
186
187 46
        if ($backgroundColor) {
188 4
            $isBackgroundColorRegistered = isset($this->registeredFills[$backgroundColor]);
189
190
            // We need to track the already registered background definitions
191 4
            if ($isBackgroundColorRegistered) {
192 2
                $registeredStyleId = $this->registeredFills[$backgroundColor];
193 2
                $registeredFillId = $this->styleIdToFillMappingTable[$registeredStyleId];
194 2
                $this->styleIdToFillMappingTable[$styleId] = $registeredFillId;
195
            } else {
196 4
                $this->registeredFills[$backgroundColor] = $styleId;
197 4
                $this->styleIdToFillMappingTable[$styleId] = $this->fillIndex++;
198
            }
199
        } else {
200
            // The fillId maps a style to a fill declaration
201
            // When there is no background color definition - we default to 0
202 46
            $this->styleIdToFillMappingTable[$styleId] = 0;
203
        }
204 46
    }
205
206
    /**
207
     * @param int $styleId
208
     * @return int|null Fill ID associated to the given style ID
209
     */
210 16
    public function getFillIdForStyleId($styleId)
211
    {
212 16
        return (isset($this->styleIdToFillMappingTable[$styleId])) ?
213 16
            $this->styleIdToFillMappingTable[$styleId] :
214 16
            null;
215
    }
216
217
    /**
218
     * Register a border definition
219
     *
220
     * @param Style $style
221
     */
222 46
    private function registerBorder(Style $style)
223
    {
224 46
        $styleId = $style->getId();
225
226 46
        if ($style->shouldApplyBorder()) {
227 5
            $border = $style->getBorder();
228 5
            $serializedBorder = \serialize($border);
229
230 5
            $isBorderAlreadyRegistered = isset($this->registeredBorders[$serializedBorder]);
231
232 5
            if ($isBorderAlreadyRegistered) {
233 2
                $registeredStyleId = $this->registeredBorders[$serializedBorder];
234 2
                $registeredBorderId = $this->styleIdToBorderMappingTable[$registeredStyleId];
235 2
                $this->styleIdToBorderMappingTable[$styleId] = $registeredBorderId;
236
            } else {
237 5
                $this->registeredBorders[$serializedBorder] = $styleId;
238 5
                $this->styleIdToBorderMappingTable[$styleId] = \count($this->registeredBorders);
239
            }
240
        } else {
241
            // If no border should be applied - the mapping is the default border: 0
242 46
            $this->styleIdToBorderMappingTable[$styleId] = 0;
243
        }
244 46
    }
245
246
    /**
247
     * @param int $styleId
248
     * @return int|null Fill ID associated to the given style ID
249
     */
250 16
    public function getBorderIdForStyleId($styleId)
251
    {
252 16
        return (isset($this->styleIdToBorderMappingTable[$styleId])) ?
253 16
            $this->styleIdToBorderMappingTable[$styleId] :
254 16
            null;
255
    }
256
257
    /**
258
     * @return array
259
     */
260 40
    public function getRegisteredFills()
261
    {
262 40
        return $this->registeredFills;
263
    }
264
265
    /**
266
     * @return array
267
     */
268 40
    public function getRegisteredBorders()
269
    {
270 40
        return $this->registeredBorders;
271
    }
272
273
    /**
274
     * @return array
275
     */
276 40
    public function getRegisteredFormats()
277
    {
278 40
        return $this->registeredFormats;
279
    }
280
}
281