Failed Conditions
Pull Request — master (#3743)
by Adrien
14:08
created

Styles::castBool()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
4
5
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
6
use PhpOffice\PhpSpreadsheet\Style\Alignment;
7
use PhpOffice\PhpSpreadsheet\Style\Border;
8
use PhpOffice\PhpSpreadsheet\Style\Borders;
9
use PhpOffice\PhpSpreadsheet\Style\Color;
10
use PhpOffice\PhpSpreadsheet\Style\Fill;
11
use PhpOffice\PhpSpreadsheet\Style\Font;
12
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
13
use PhpOffice\PhpSpreadsheet\Style\Protection;
14
use PhpOffice\PhpSpreadsheet\Style\Style;
15
use SimpleXMLElement;
16
use stdClass;
17
18
class Styles extends BaseParserClass
19
{
20
    /**
21
     * Theme instance.
22
     *
23
     * @var ?Theme
24
     */
25
    private $theme;
26
27
    /** @var array */
28
    private $workbookPalette = [];
29
30
    /** @var array */
31
    private $styles = [];
32
33
    /** @var array */
34
    private $cellStyles = [];
35
36
    /** @var SimpleXMLElement */
37
    private $styleXml;
38
39
    /** @var string */
40
    private $namespace = '';
41
42 554
    public function setNamespace(string $namespace): void
43
    {
44 554
        $this->namespace = $namespace;
45
    }
46
47 554
    public function setWorkbookPalette(array $palette): void
48
    {
49 554
        $this->workbookPalette = $palette;
50
    }
51
52
    private function getStyleAttributes(SimpleXMLElement $value): SimpleXMLElement
53
    {
54
        $attr = $value->attributes('');
55 557
        if ($attr === null || count($attr) === 0) {
56
            $attr = $value->attributes($this->namespace);
57 557
        }
58
59
        return Xlsx::testSimpleXml($attr);
60 557
    }
61
62 557
    public function setStyleXml(SimpleXmlElement $styleXml): void
63 557
    {
64 557
        $this->styleXml = $styleXml;
65 557
    }
66 549
67
    public function setTheme(Theme $theme): void
68
    {
69
        $this->theme = $theme;
70 557
    }
71
72
    public function setStyleBaseData(?Theme $theme = null, array $styles = [], array $cellStyles = []): void
73 554
    {
74
        $this->theme = $theme;
75 554
        $this->styles = $styles;
76
        $this->cellStyles = $cellStyles;
77
    }
78 544
79
    public function readFontStyle(Font $fontStyle, SimpleXMLElement $fontStyleXml): void
80 544
    {
81
        if (isset($fontStyleXml->name)) {
82
            $attr = $this->getStyleAttributes($fontStyleXml->name);
83 554
            if (isset($attr['val'])) {
84
                $fontStyle->setName((string) $attr['val']);
85 554
            }
86 554
        }
87 554
        if (isset($fontStyleXml->sz)) {
88
            $attr = $this->getStyleAttributes($fontStyleXml->sz);
89
            if (isset($attr['val'])) {
90 553
                $fontStyle->setSize((float) $attr['val']);
91
            }
92 553
        }
93 552
        if (isset($fontStyleXml->b)) {
94 552
            $attr = $this->getStyleAttributes($fontStyleXml->b);
95 552
            $fontStyle->setBold(!isset($attr['val']) || self::boolean((string) $attr['val']));
96
        }
97
        if (isset($fontStyleXml->i)) {
98 553
            $attr = $this->getStyleAttributes($fontStyleXml->i);
99 552
            $fontStyle->setItalic(!isset($attr['val']) || self::boolean((string) $attr['val']));
100 552
        }
101 552
        if (isset($fontStyleXml->strike)) {
102
            $attr = $this->getStyleAttributes($fontStyleXml->strike);
103
            $fontStyle->setStrikethrough(!isset($attr['val']) || self::boolean((string) $attr['val']));
104 553
        }
105 446
        $fontStyle->getColor()->setARGB($this->readColor($fontStyleXml->color));
106 446
107
        if (isset($fontStyleXml->u)) {
108 553
            $attr = $this->getStyleAttributes($fontStyleXml->u);
109 412
            if (!isset($attr['val'])) {
110 412
                $fontStyle->setUnderline(Font::UNDERLINE_SINGLE);
111
            } else {
112 553
                $fontStyle->setUnderline((string) $attr['val']);
113 393
            }
114 393
        }
115
        if (isset($fontStyleXml->vertAlign)) {
116 553
            $attr = $this->getStyleAttributes($fontStyleXml->vertAlign);
117
            if (isset($attr['val'])) {
118 553
                $verticalAlign = strtolower((string) $attr['val']);
119 405
                if ($verticalAlign === 'superscript') {
120 405
                    $fontStyle->setSuperscript(true);
121 196
                } elseif ($verticalAlign === 'subscript') {
122
                    $fontStyle->setSubscript(true);
123 389
                }
124
            }
125
        }
126 553
        if (isset($fontStyleXml->scheme)) {
127 22
            $attr = $this->getStyleAttributes($fontStyleXml->scheme);
128 22
            $fontStyle->setScheme((string) $attr['val']);
129 22
        }
130 22
    }
131 2
132 22
    private function readNumberFormat(NumberFormat $numfmtStyle, SimpleXMLElement $numfmtStyleXml): void
133 2
    {
134
        if ((string) $numfmtStyleXml['formatCode'] !== '') {
135
            $numfmtStyle->setFormatCode(self::formatGeneral((string) $numfmtStyleXml['formatCode']));
136
137 553
            return;
138 327
        }
139 327
        $numfmt = $this->getStyleAttributes($numfmtStyleXml);
140
        if (isset($numfmt['formatCode'])) {
141
            $numfmtStyle->setFormatCode(self::formatGeneral((string) $numfmt['formatCode']));
142
        }
143 221
    }
144
145 221
    public function readFillStyle(Fill $fillStyle, SimpleXMLElement $fillStyleXml): void
146
    {
147
        if ($fillStyleXml->gradientFill) {
148
            /** @var SimpleXMLElement $gradientFill */
149
            $gradientFill = $fillStyleXml->gradientFill[0];
150 221
            $attr = $this->getStyleAttributes($gradientFill);
151 221
            if (!empty($attr['type'])) {
152 196
                $fillStyle->setFillType((string) $attr['type']);
153
            }
154
            $fillStyle->setRotation((float) ($attr['degree']));
155
            $gradientFill->registerXPathNamespace('sml', Namespaces::MAIN);
156 553
            $fillStyle->getStartColor()->setARGB($this->readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=0]'))->color));
157
            $fillStyle->getEndColor()->setARGB($this->readColor(self::getArrayItem($gradientFill->xpath('sml:stop[@position=1]'))->color));
158 553
        } elseif ($fillStyleXml->patternFill) {
159
            $defaultFillStyle = Fill::FILL_NONE;
160 3
            if ($fillStyleXml->patternFill->fgColor) {
161 3
                $fillStyle->getStartColor()->setARGB($this->readColor($fillStyleXml->patternFill->fgColor, true));
162 3
                $defaultFillStyle = Fill::FILL_SOLID;
163 2
            }
164
            if ($fillStyleXml->patternFill->bgColor) {
165 3
                $fillStyle->getEndColor()->setARGB($this->readColor($fillStyleXml->patternFill->bgColor, true));
166 3
                $defaultFillStyle = Fill::FILL_SOLID;
167 3
            }
168 3
169 553
            $type = '';
170 552
            if ((string) $fillStyleXml->patternFill['patternType'] !== '') {
171 552
                $type = (string) $fillStyleXml->patternFill['patternType'];
172 246
            } else {
173 246
                $attr = $this->getStyleAttributes($fillStyleXml->patternFill);
174
                $type = (string) $attr['patternType'];
175 552
            }
176 257
            $patternType = ($type === '') ? $defaultFillStyle : $type;
177 257
178
            $fillStyle->setFillType($patternType);
179
        }
180 552
    }
181 552
182
    public function readBorderStyle(Borders $borderStyle, SimpleXMLElement $borderStyleXml): void
183
    {
184 552
        $diagonalUp = $this->getAttribute($borderStyleXml, 'diagonalUp');
185 552
        $diagonalUp = self::boolean($diagonalUp);
186
        $diagonalDown = $this->getAttribute($borderStyleXml, 'diagonalDown');
187 552
        $diagonalDown = self::boolean($diagonalDown);
188
        if ($diagonalUp === false) {
189 552
            if ($diagonalDown === false) {
190
                $borderStyle->setDiagonalDirection(Borders::DIAGONAL_NONE);
191
            } else {
192
                $borderStyle->setDiagonalDirection(Borders::DIAGONAL_DOWN);
193 553
            }
194
        } elseif ($diagonalDown === false) {
195 553
            $borderStyle->setDiagonalDirection(Borders::DIAGONAL_UP);
196 553
        } else {
197 553
            $borderStyle->setDiagonalDirection(Borders::DIAGONAL_BOTH);
198 553
        }
199 553
200 553
        if (isset($borderStyleXml->left)) {
201 553
            $this->readBorder($borderStyle->getLeft(), $borderStyleXml->left);
202
        }
203 553
        if (isset($borderStyleXml->right)) {
204
            $this->readBorder($borderStyle->getRight(), $borderStyleXml->right);
205 2
        }
206 1
        if (isset($borderStyleXml->top)) {
207
            $this->readBorder($borderStyle->getTop(), $borderStyleXml->top);
208 1
        }
209
        if (isset($borderStyleXml->bottom)) {
210
            $this->readBorder($borderStyle->getBottom(), $borderStyleXml->bottom);
211 553
        }
212 546
        if (isset($borderStyleXml->diagonal)) {
213
            $this->readBorder($borderStyle->getDiagonal(), $borderStyleXml->diagonal);
214 553
        }
215 545
    }
216
217 553
    private function getAttribute(SimpleXMLElement $xml, string $attribute): string
218 547
    {
219
        $style = '';
220 553
        if ((string) $xml[$attribute] !== '') {
221 546
            $style = (string) $xml[$attribute];
222
        } else {
223 553
            $attr = $this->getStyleAttributes($xml);
224 543
            if (isset($attr[$attribute])) {
225
                $style = (string) $attr[$attribute];
226
            }
227
        }
228 553
229
        return $style;
230 553
    }
231 553
232
    private function readBorder(Border $border, SimpleXMLElement $borderXml): void
233
    {
234 553
        $style = $this->getAttribute($borderXml, 'style');
235 553
        if ($style !== '') {
236 307
            $border->setBorderStyle((string) $style);
237
        } else {
238
            $border->setBorderStyle(Border::BORDER_NONE);
239
        }
240 553
        if (isset($borderXml->color)) {
241
            $border->getColor()->setARGB($this->readColor($borderXml->color));
242
        }
243 547
    }
244
245 547
    public function readAlignmentStyle(Alignment $alignment, SimpleXMLElement $alignmentXml): void
246 547
    {
247 69
        $horizontal = (string) $this->getAttribute($alignmentXml, 'horizontal');
248
        if ($horizontal !== '') {
249 546
            $alignment->setHorizontal($horizontal);
250
        }
251 547
        $vertical = (string) $this->getAttribute($alignmentXml, 'vertical');
252 67
        if ($vertical !== '') {
253
            $alignment->setVertical($vertical);
254
        }
255
256 553
        $textRotation = (int) $this->getAttribute($alignmentXml, 'textRotation');
257
        if ($textRotation > 90) {
258 553
            $textRotation = 90 - $textRotation;
259 553
        }
260 285
        $alignment->setTextRotation($textRotation);
261
262 553
        $wrapText = $this->getAttribute($alignmentXml, 'wrapText');
263 553
        $alignment->setWrapText(self::boolean((string) $wrapText));
264 261
        $shrinkToFit = $this->getAttribute($alignmentXml, 'shrinkToFit');
265
        $alignment->setShrinkToFit(self::boolean((string) $shrinkToFit));
266
        $indent = (int) $this->getAttribute($alignmentXml, 'indent');
267 553
        $alignment->setIndent(max($indent, 0));
268 553
        $readingOrder = (int) $this->getAttribute($alignmentXml, 'readingOrder');
269 1
        $alignment->setReadOrder(max($readingOrder, 0));
270
    }
271 553
272
    private static function formatGeneral(string $formatString): string
273 553
    {
274 553
        if ($formatString === 'GENERAL') {
275 553
            $formatString = NumberFormat::FORMAT_GENERAL;
276 553
        }
277 553
278 553
        return $formatString;
279 553
    }
280 553
281
    /**
282
     * Read style.
283 553
     *
284
     * @param SimpleXMLElement|stdClass $style
285 553
     */
286 1
    public function readStyle(Style $docStyle, $style): void
287
    {
288
        if ($style instanceof SimpleXMLElement) {
289 553
            $this->readNumberFormat($docStyle->getNumberFormat(), $style->numFmt);
290
        } else {
291
            $docStyle->getNumberFormat()->setFormatCode(self::formatGeneral((string) $style->numFmt));
292
        }
293
294
        if (isset($style->font)) {
295
            $this->readFontStyle($docStyle->getFont(), $style->font);
296
        }
297 553
298
        if (isset($style->fill)) {
299 553
            $this->readFillStyle($docStyle->getFill(), $style->fill);
300 221
        }
301
302 553
        if (isset($style->border)) {
303
            $this->readBorderStyle($docStyle->getBorders(), $style->border);
304
        }
305 553
306 553
        if (isset($style->alignment)) {
307
            $this->readAlignmentStyle($docStyle->getAlignment(), $style->alignment);
308
        }
309 553
310 553
        // protection
311
        if (isset($style->protection)) {
312
            $this->readProtectionLocked($docStyle, $style->protection);
313 553
            $this->readProtectionHidden($docStyle, $style->protection);
314 553
        }
315
316
        // top-level style settings
317 553
        if (isset($style->quotePrefix)) {
318 553
            $docStyle->setQuotePrefix((bool) $style->quotePrefix);
319
        }
320
    }
321
322 553
    /**
323 553
     * Read protection locked attribute.
324 553
     */
325
    public function readProtectionLocked(Style $docStyle, SimpleXMLElement $style): void
326
    {
327
        $locked = '';
328 553
        if ((string) $style['locked'] !== '') {
329 553
            $locked = (string) $style['locked'];
330
        } else {
331
            $attr = $this->getStyleAttributes($style);
332
            if (isset($attr['locked'])) {
333
                $locked = (string) $attr['locked'];
334
            }
335
        }
336 553
        if ($locked !== '') {
337
            if (self::boolean($locked)) {
338 553
                $docStyle->getProtection()->setLocked(Protection::PROTECTION_PROTECTED);
339 553
            } else {
340
                $docStyle->getProtection()->setLocked(Protection::PROTECTION_UNPROTECTED);
341
            }
342 553
        }
343 553
    }
344 27
345
    /**
346
     * Read protection hidden attribute.
347 553
     */
348 27
    public function readProtectionHidden(Style $docStyle, SimpleXMLElement $style): void
349 10
    {
350
        $hidden = '';
351 17
        if ((string) $style['hidden'] !== '') {
352
            $hidden = (string) $style['hidden'];
353
        } else {
354
            $attr = $this->getStyleAttributes($style);
355
            if (isset($attr['hidden'])) {
356
                $hidden = (string) $attr['hidden'];
357
            }
358
        }
359 553
        if ($hidden !== '') {
360
            if (self::boolean((string) $hidden)) {
361 553
                $docStyle->getProtection()->setHidden(Protection::PROTECTION_PROTECTED);
362 553
            } else {
363
                $docStyle->getProtection()->setHidden(Protection::PROTECTION_UNPROTECTED);
364
            }
365 553
        }
366 553
    }
367 15
368
    public function readColor(SimpleXMLElement $color, bool $background = false): string
369
    {
370 553
        $attr = $this->getStyleAttributes($color);
371 15
        if (isset($attr['rgb'])) {
372 1
            return (string) $attr['rgb'];
373
        }
374 14
        if (isset($attr['indexed'])) {
375
            $indexedColor = (int) $attr['indexed'];
376
            if ($indexedColor >= count($this->workbookPalette)) {
377
                return Color::indexedColor($indexedColor - 7, $background)->getARGB() ?? '';
378
            }
379 557
380
            return Color::indexedColor($indexedColor, $background, $this->workbookPalette)->getARGB() ?? '';
381 557
        }
382 557
        if (isset($attr['theme'])) {
383 480
            if ($this->theme !== null) {
384
                $returnColour = $this->theme->getColourByIndex((int) $attr['theme']);
385 359
                if (isset($attr['tint'])) {
386 88
                    $tintAdjust = (float) $attr['tint'];
387 88
                    $returnColour = Color::changeBrightness($returnColour ?? '', $tintAdjust);
388 85
                }
389
390
                return 'FF' . $returnColour;
391 4
            }
392
        }
393 352
394 330
        return ($background) ? 'FFFFFFFF' : 'FF000000';
395 329
    }
396 329
397 204
    public function dxfs(bool $readDataOnly = false): array
398 204
    {
399
        $dxfs = [];
400
        if (!$readDataOnly && $this->styleXml) {
401 329
            //    Conditional Styles
402
            if ($this->styleXml->dxfs) {
403
                foreach ($this->styleXml->dxfs->dxf as $dxf) {
404
                    $style = new Style(false, true);
405 49
                    $this->readStyle($style, $dxf);
406
                    $dxfs[] = $style;
407
                }
408 554
            }
409
            //    Cell Styles
410 554
            if ($this->styleXml->cellStyles) {
411 554
                foreach ($this->styleXml->cellStyles->cellStyle as $cellStylex) {
412
                    $cellStyle = Xlsx::getAttributes($cellStylex);
413 553
                    if ((int) ($cellStyle['builtinId']) == 0) {
414 541
                        if (isset($this->cellStyles[(int) ($cellStyle['xfId'])])) {
415 221
                            // Set default style
416 221
                            $style = new Style();
417 221
                            $this->readStyle($style, $this->cellStyles[(int) ($cellStyle['xfId'])]);
418
419
                            // normal style, currently not using it for anything
420
                        }
421 553
                    }
422 550
                }
423 550
            }
424 550
        }
425 550
426
        return $dxfs;
427 550
    }
428 550
429
    public function styles(): array
430
    {
431
        return $this->styles;
432
    }
433
434
    /**
435
     * Get array item.
436
     *
437 554
     * @param mixed $array (usually array, in theory can be false)
438
     *
439
     * @return stdClass
440 554
     */
441
    private static function getArrayItem(mixed $array, int $key = 0)
442 554
    {
443
        return is_array($array) ? ($array[$key] ?? null) : null;
444
    }
445
}
446