StyleSheet::xmlCellXfs()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 0
dl 0
loc 10
ccs 9
cts 9
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Eclipxe\XlsxExporter;
6
7
use InvalidArgumentException;
8
9
class StyleSheet
10
{
11
    /** @var Style[] */
12
    protected array $styles;
13
14
    /** @var array<string, array<int, string>> */
15
    protected array $hashes = [];
16
17
    /** @var array<string, array<int, Styles\StyleInterface>> */
18
    protected $objects;
19
20 5
    public function __construct(Style ...$styles)
21
    {
22 5
        if ([] === $styles) {
23 1
            throw new InvalidArgumentException('Error creating the stylesheet, no styles found');
24
        }
25
        // mandatory styles
26 4
        $this->styles = array_merge($this->mandatoryStyles(), array_values($styles));
27
    }
28
29
    /**
30
     * The mandatory styles, must be declared before any other style
31
     *
32
     * @return array<int, Style>
33
     */
34 4
    protected function mandatoryStyles(): array
35
    {
36 4
        return [
37 4
            new Style([
38 4
                'format' => [
39 4
                    'code' => Styles\Format::FORMAT_GENERAL,
40 4
                ],
41 4
                'fill' => [
42 4
                    'pattern' => Styles\Fill::NONE,
43 4
                ],
44 4
                'alignment' => [
45 4
                    'horizontal' => Styles\Alignment::HORIZONTAL_GENERAL,
46 4
                    'vertical' => Styles\Alignment::VERTICAL_BOTTOM,
47 4
                ],
48 4
            ]),
49 4
            new Style([
50 4
                'fill' => [
51 4
                    'pattern' => Styles\Fill::GRAY125,
52 4
                ],
53 4
            ]),
54 4
        ];
55
    }
56
57 4
    protected function processStylesFormat(): void
58
    {
59 4
        $codes = [];
60 4
        $fmtcounter = 164;
61 4
        $this->objects['format'] = [];
62 4
        $this->hashes['format'] = [];
63 4
        foreach ($this->styles as $style) {
64 4
            $format = $style->getFormat();
65 4
            if (! $format->hasValues()) {
66 4
                $format->code = Styles\Format::FORMAT_GENERAL;
67
            }
68 4
            if (false !== $builtin = $format->getBuiltInCodeIdByCode($format->code)) {
69 4
                $format->id = $builtin;
70 4
                if (! in_array($format->code, $codes, true)) {
71 4
                    $codes[$format->id] = $format->code;
72 4
                    $this->objects['format'][] = $format;
73
                }
74 2
            } elseif (false !== $numfmtid = array_search($format->code, $codes, true)) {
75 1
                $format->id = $numfmtid;
76
            } else {
77 2
                $format->id = $fmtcounter;
78 2
                $fmtcounter = $fmtcounter + 1;
79 2
                $codes[$format->id] = $format->code;
80 2
                $this->objects['format'][] = $format;
81
            }
82
        }
83
    }
84
85 4
    protected function processAddToArray(string $name, Styles\StyleInterface $generic): void
86
    {
87 4
        $generic->setIndex(0);
88 4
        if ($generic->hasValues()) {
89 4
            $hash = $generic->getHash();
90 4
            if (false === $index = array_search($hash, $this->hashes[$name], true)) {
91 4
                $index = count($this->hashes[$name]);
92 4
                $this->hashes[$name][] = $hash;
93 4
                $this->objects[$name][] = $generic;
94
            }
95 4
            $generic->setIndex($index);
0 ignored issues
show
Bug introduced by
It seems like $index can also be of type string; however, parameter $index of Eclipxe\XlsxExporter\Sty...leInterface::setIndex() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
            $generic->setIndex(/** @scrutinizer ignore-type */ $index);
Loading history...
96
        }
97
    }
98
99 4
    protected function processStyles(): void
100
    {
101
        // different process for "format"
102 4
        $this->processStylesFormat();
103
        // same process for "font", "fill" and "border"
104 4
        $namedcollections = ['font', 'fill', 'border'];
105 4
        foreach ($namedcollections as $name) {
106 4
            $this->objects[$name] = [];
107 4
            $this->hashes[$name] = []; // init styles
108
        }
109 4
        foreach ($this->styles as $style) {
110 4
            $style->setStyleIndex(0);
111 4
            foreach ($namedcollections as $name) {
112 4
                $method = 'get' . ucfirst($name);
113 4
                $this->processAddToArray($name, $style->$method());
114
            }
115
        }
116
    }
117
118 4
    protected function xmlCollection(string $name, string $tag): string
119
    {
120 4
        return '<' . $tag . ' count="' . count($this->objects[$name]) . '">'
121 4
            . array_reduce($this->objects[$name], fn ($return, Styles\StyleInterface $generic): string => $return . $generic->asXML())
122 4
            . '</' . $tag . '>'
123 4
        ;
124
    }
125
126 4
    protected function xmlCellStylesXF(): string
127
    {
128 4
        return '<cellStyleXfs count="1">'
129 4
            . '<xf numFmtId="0" fontId="0" fillId="0" borderId="0"/>'
130 4
            . '</cellStyleXfs>'
131 4
        ;
132
    }
133
134 4
    protected function xmlCellXfs(): string
135
    {
136 4
        $index = 0;
137 4
        return '<cellXfs count="' . count($this->styles) . '">'
138 4
            . array_reduce($this->styles, function ($return, Style $style) use (&$index): string {
139 4
                $style->setStyleIndex($index);
140 4
                $index = $index + 1;
141 4
                return $return . $style->asXML();
142 4
            })
143 4
            . '</cellXfs>'
144 4
        ;
145
    }
146
147
    /**
148
     * Return the content of the style sheet in xml format
149
     */
150 4
    public function asXML(): string
151
    {
152 4
        $this->processStyles();
153 4
        return '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' . "\n"
154 4
            . '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">'
155 4
            . $this->xmlCollection('format', 'numFmts')
156 4
            . $this->xmlCollection('font', 'fonts')
157 4
            . $this->xmlCollection('fill', 'fills')
158 4
            // . $this->xmlCollection("border", "borders")
159 4
            . '<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>'
160 4
            . $this->xmlCellStylesXF()
161 4
            . $this->xmlCellXfs()
162 4
            . '<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>'
163 4
            . '<dxfs count="0"/>'
164 4
            . '</styleSheet>'
165 4
        ;
166
    }
167
168
    /**
169
     * Styles collection
170
     * @return Style[]
171
     */
172
    public function getStyles(): array
173
    {
174
        return $this->styles;
175
    }
176
}
177