Failed Conditions
Pull Request — master (#4412)
by
unknown
14:08
created

Styles::tableStyles()   B

Complexity

Conditions 11
Paths 3

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 11

Importance

Changes 0
Metric Value
eloc 23
dl 0
loc 37
rs 7.3166
c 0
b 0
f 0
ccs 3
cts 3
cp 1
cc 11
nc 3
nop 1
crap 11

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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