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