Passed
Push — spaghetti ( d276c8...efb1b1 )
by simpletoimplement
02:30
created

Styles::processRewind()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types = 1);
2
3
namespace Spaghetti\XLSXParser;
4
5
use XMLReader;
6
7
use function in_array;
8
use function preg_match;
9
10
/**
11
 * @internal
12
 */
13
final class Styles extends AbstractXMLDictionary
14
{
15
    public const FORMAT_DATE = 1;
16
    private const FORMAT_DEFAULT = 0;
17
18
    private array $nativeDateFormats = [14, 15, 16, 17, 18, 19, 20, 21, 22, ];
19
    private array $numberFormats = [];
20
    private bool $inXfs = false;
21
    private bool $needsRewind;
22
23
    protected function readNext(): void
24
    {
25
        $xml = $this->getXMLReader();
26
27
        while ($xml->read()) {
28
            if ('cellXfs' === $xml->name) {
29
                switch ($xml->nodeType) {
30
                    case XMLReader::END_ELEMENT:
31
                        break 2;
32
                    case XMLReader::ELEMENT:
33
                        $this->inXfs = true;
34
                        continue 2;
35
                }
36
            }
37
38
            $this->xfs(xml: $xml);
39
        }
40
41
        $this->valid = false;
42
        $this->closeXMLReader();
43
    }
44
45
    protected function createXMLReader(): XMLReader
46
    {
47
        $xml = parent::createXMLReader();
48
        $this->needsRewind = false;
49
50
        while ($xml->read()) {
51
            if (XMLReader::END_ELEMENT === $xml->nodeType && 'numFmts' === $xml->name) {
52
                break;
53
            }
54
55
            if (XMLReader::ELEMENT === $xml->nodeType) {
56
                $this->process(xml: $xml);
57
            }
58
        }
59
60
        $this->processRewind(xml: $xml);
61
62
        return $xml;
63
    }
64
65
    private function processRewind(XMLReader &$xml): void
66
    {
67
        if ($this->needsRewind) {
68
            $xml->close();
69
            $xml = parent::createXMLReader();
70
        }
71
    }
72
73
    private function xfs(XMLReader $xml): void
74
    {
75
        if ($this->inXfs && XMLReader::ELEMENT === $xml->nodeType && 'xf' === $xml->name) {
76
            $this->values[] = $this->getValue(fmtId: (int) $xml->getAttribute(name: 'numFmtId'));
77
        }
78
    }
79
80
    private function process(XMLReader $xml): void
81
    {
82
        match ($xml->name) {
83
            'cellXfs' => $this->needsRewind = true,
84
            'numFmt' => $this->numberFormats[$xml->getAttribute(name: 'numFmtId')] = $this->matchDateFormat(xml: $xml),
85
            default => null,
86
        };
87
    }
88
89
    private function matchDateFormat(XMLReader $xml): int
90
    {
91
        return preg_match(pattern: '{^(\[\$[[:alpha:]]*-[0-9A-F]*\])*[hmsdy]}i', subject: $xml->getAttribute(name: 'formatCode')) ? self::FORMAT_DATE : self::FORMAT_DEFAULT;
92
    }
93
94
    private function getValue(int $fmtId): int
95
    {
96
        return match (true) {
97
            in_array(needle: $fmtId, haystack: $this->nativeDateFormats, strict: true) => self::FORMAT_DATE,
98
            isset($this->numberFormats[$fmtId]) => $this->numberFormats[$fmtId],
99
            default => self::FORMAT_DEFAULT,
100
        };
101
    }
102
}
103