Failed Conditions
Push — master ( 11f758...e55052 )
by Adrien
18:18 queued 05:56
created

Styles::read()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 2
b 0
f 0
nc 2
nop 3
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 2
rs 10
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Reader\Gnumeric;
4
5
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
6
use PhpOffice\PhpSpreadsheet\Shared\Date;
7
use PhpOffice\PhpSpreadsheet\Spreadsheet;
8
use PhpOffice\PhpSpreadsheet\Style\Alignment;
9
use PhpOffice\PhpSpreadsheet\Style\Border;
10
use PhpOffice\PhpSpreadsheet\Style\Borders;
11
use PhpOffice\PhpSpreadsheet\Style\Fill;
12
use PhpOffice\PhpSpreadsheet\Style\Font;
13
use SimpleXMLElement;
14
15
class Styles
16
{
17
    /**
18
     * @var Spreadsheet
19
     */
20
    private $spreadsheet;
21
22
    /**
23
     * @var bool
24
     */
25
    protected $readDataOnly = false;
26
27
    /** @var array */
28
    public static $mappings = [
29
        'borderStyle' => [
30
            '0' => Border::BORDER_NONE,
31
            '1' => Border::BORDER_THIN,
32
            '2' => Border::BORDER_MEDIUM,
33
            '3' => Border::BORDER_SLANTDASHDOT,
34
            '4' => Border::BORDER_DASHED,
35
            '5' => Border::BORDER_THICK,
36
            '6' => Border::BORDER_DOUBLE,
37
            '7' => Border::BORDER_DOTTED,
38
            '8' => Border::BORDER_MEDIUMDASHED,
39
            '9' => Border::BORDER_DASHDOT,
40
            '10' => Border::BORDER_MEDIUMDASHDOT,
41
            '11' => Border::BORDER_DASHDOTDOT,
42
            '12' => Border::BORDER_MEDIUMDASHDOTDOT,
43
            '13' => Border::BORDER_MEDIUMDASHDOTDOT,
44
        ],
45
        'fillType' => [
46
            '1' => Fill::FILL_SOLID,
47
            '2' => Fill::FILL_PATTERN_DARKGRAY,
48
            '3' => Fill::FILL_PATTERN_MEDIUMGRAY,
49
            '4' => Fill::FILL_PATTERN_LIGHTGRAY,
50
            '5' => Fill::FILL_PATTERN_GRAY125,
51
            '6' => Fill::FILL_PATTERN_GRAY0625,
52
            '7' => Fill::FILL_PATTERN_DARKHORIZONTAL, // horizontal stripe
53
            '8' => Fill::FILL_PATTERN_DARKVERTICAL, // vertical stripe
54
            '9' => Fill::FILL_PATTERN_DARKDOWN, // diagonal stripe
55
            '10' => Fill::FILL_PATTERN_DARKUP, // reverse diagonal stripe
56
            '11' => Fill::FILL_PATTERN_DARKGRID, // diagoanl crosshatch
57
            '12' => Fill::FILL_PATTERN_DARKTRELLIS, // thick diagonal crosshatch
58
            '13' => Fill::FILL_PATTERN_LIGHTHORIZONTAL,
59
            '14' => Fill::FILL_PATTERN_LIGHTVERTICAL,
60
            '15' => Fill::FILL_PATTERN_LIGHTUP,
61
            '16' => Fill::FILL_PATTERN_LIGHTDOWN,
62
            '17' => Fill::FILL_PATTERN_LIGHTGRID, // thin horizontal crosshatch
63
            '18' => Fill::FILL_PATTERN_LIGHTTRELLIS, // thin diagonal crosshatch
64
        ],
65
        'horizontal' => [
66
            '1' => Alignment::HORIZONTAL_GENERAL,
67
            '2' => Alignment::HORIZONTAL_LEFT,
68
            '4' => Alignment::HORIZONTAL_RIGHT,
69
            '8' => Alignment::HORIZONTAL_CENTER,
70
            '16' => Alignment::HORIZONTAL_CENTER_CONTINUOUS,
71
            '32' => Alignment::HORIZONTAL_JUSTIFY,
72
            '64' => Alignment::HORIZONTAL_CENTER_CONTINUOUS,
73
        ],
74
        'underline' => [
75
            '1' => Font::UNDERLINE_SINGLE,
76
            '2' => Font::UNDERLINE_DOUBLE,
77
            '3' => Font::UNDERLINE_SINGLEACCOUNTING,
78
            '4' => Font::UNDERLINE_DOUBLEACCOUNTING,
79
        ],
80
        'vertical' => [
81
            '1' => Alignment::VERTICAL_TOP,
82
            '2' => Alignment::VERTICAL_BOTTOM,
83
            '4' => Alignment::VERTICAL_CENTER,
84
            '8' => Alignment::VERTICAL_JUSTIFY,
85
        ],
86
    ];
87
88 10
    public function __construct(Spreadsheet $spreadsheet, bool $readDataOnly)
89
    {
90 10
        $this->spreadsheet = $spreadsheet;
91 10
        $this->readDataOnly = $readDataOnly;
92 10
    }
93
94 10
    public function read(SimpleXMLElement $sheet, int $maxRow, int $maxCol): void
95
    {
96 10
        if ($sheet->Styles->StyleRegion !== null) {
97 10
            $this->readStyles($sheet->Styles->StyleRegion, $maxRow, $maxCol);
98
        }
99 10
    }
100
101 10
    private function readStyles(SimpleXMLElement $styleRegion, int $maxRow, int $maxCol): void
102
    {
103 10
        foreach ($styleRegion as $style) {
104 10
            $styleAttributes = $style->attributes();
1 ignored issue
show
Bug introduced by
The method attributes() does not exist on null. ( Ignorable by Annotation )

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

104
            /** @scrutinizer ignore-call */ 
105
            $styleAttributes = $style->attributes();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
105 10
            if ($styleAttributes !== null && ($styleAttributes['startRow'] <= $maxRow) && ($styleAttributes['startCol'] <= $maxCol)) {
106 10
                $cellRange = $this->readStyleRange($styleAttributes, $maxCol, $maxRow);
107
108 10
                $styleAttributes = $style->Style->attributes();
109
110 10
                $styleArray = [];
111
                // We still set the number format mask for date/time values, even if readDataOnly is true
112
                //    so that we can identify whether a float is a float or a date value
113 10
                $formatCode = $styleAttributes ? (string) $styleAttributes['Format'] : null;
114 10
                if ($formatCode && Date::isDateTimeFormatCode($formatCode)) {
115 5
                    $styleArray['numberFormat']['formatCode'] = $formatCode;
116
                }
117 10
                if ($this->readDataOnly === false && $styleAttributes !== null) {
118
                    //    If readDataOnly is false, we set all formatting information
119 10
                    $styleArray['numberFormat']['formatCode'] = $formatCode;
120 10
                    $styleArray = $this->readStyle($styleArray, $styleAttributes, $style);
1 ignored issue
show
Bug introduced by
It seems like $style can also be of type null; however, parameter $style of PhpOffice\PhpSpreadsheet...ric\Styles::readStyle() does only seem to accept SimpleXMLElement, 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

120
                    $styleArray = $this->readStyle($styleArray, $styleAttributes, /** @scrutinizer ignore-type */ $style);
Loading history...
121
                }
122 10
                $this->spreadsheet->getActiveSheet()->getStyle($cellRange)->applyFromArray($styleArray);
123
            }
124
        }
125 10
    }
126
127 6
    private function addBorderDiagonal(SimpleXMLElement $srssb, array &$styleArray): void
128
    {
129 6
        if (isset($srssb->Diagonal, $srssb->{'Rev-Diagonal'})) {
130 6
            $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->Diagonal->attributes());
131 6
            $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_BOTH;
132 4
        } elseif (isset($srssb->Diagonal)) {
133 4
            $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->Diagonal->attributes());
134 4
            $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_UP;
135 4
        } elseif (isset($srssb->{'Rev-Diagonal'})) {
136 4
            $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->{'Rev-Diagonal'}->attributes());
137 4
            $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_DOWN;
138
        }
139 6
    }
140
141 6
    private function addBorderStyle(SimpleXMLElement $srssb, array &$styleArray, string $direction): void
142
    {
143 6
        $ucDirection = ucfirst($direction);
144 6
        if (isset($srssb->$ucDirection)) {
145 6
            $styleArray['borders'][$direction] = self::parseBorderAttributes($srssb->$ucDirection->attributes());
146
        }
147 6
    }
148
149 10
    private function calcRotation(SimpleXMLElement $styleAttributes): int
150
    {
151 10
        $rotation = (int) $styleAttributes->Rotation;
152 10
        if ($rotation >= 270 && $rotation <= 360) {
153 4
            $rotation -= 360;
154
        }
155 10
        $rotation = (abs($rotation) > 90) ? 0 : $rotation;
156
157 10
        return $rotation;
158
    }
159
160 6
    private static function addStyle(array &$styleArray, string $key, string $value): void
161
    {
162 6
        if (array_key_exists($value, self::$mappings[$key])) {
163 6
            $styleArray[$key] = self::$mappings[$key][$value];
164
        }
165 6
    }
166
167 10
    private static function addStyle2(array &$styleArray, string $key1, string $key, string $value): void
168
    {
169 10
        if (array_key_exists($value, self::$mappings[$key])) {
170 6
            $styleArray[$key1][$key] = self::$mappings[$key][$value];
171
        }
172 10
    }
173
174 6
    private static function parseBorderAttributes(?SimpleXMLElement $borderAttributes): array
175
    {
176 6
        $styleArray = [];
177 6
        if ($borderAttributes !== null) {
178 6
            if (isset($borderAttributes['Color'])) {
179 4
                $styleArray['color']['rgb'] = self::parseGnumericColour($borderAttributes['Color']);
180
            }
181
182 6
            self::addStyle($styleArray, 'borderStyle', (string) $borderAttributes['Style']);
183
        }
184
185 6
        return $styleArray;
186
    }
187
188 10
    private static function parseGnumericColour(string $gnmColour): string
189
    {
190 10
        [$gnmR, $gnmG, $gnmB] = explode(':', $gnmColour);
191 10
        $gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2);
192 10
        $gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2);
193 10
        $gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2);
194
195 10
        return $gnmR . $gnmG . $gnmB;
196
    }
197
198 10
    private function addColors(array &$styleArray, SimpleXMLElement $styleAttributes): void
199
    {
200 10
        $RGB = self::parseGnumericColour((string) $styleAttributes['Fore']);
201 10
        $styleArray['font']['color']['rgb'] = $RGB;
202 10
        $RGB = self::parseGnumericColour((string) $styleAttributes['Back']);
203 10
        $shade = (string) $styleAttributes['Shade'];
204 10
        if (($RGB !== '000000') || ($shade !== '0')) {
205 10
            $RGB2 = self::parseGnumericColour((string) $styleAttributes['PatternColor']);
206 10
            if ($shade === '1') {
207 4
                $styleArray['fill']['startColor']['rgb'] = $RGB;
208 4
                $styleArray['fill']['endColor']['rgb'] = $RGB2;
209
            } else {
210 10
                $styleArray['fill']['endColor']['rgb'] = $RGB;
211 10
                $styleArray['fill']['startColor']['rgb'] = $RGB2;
212
            }
213 10
            self::addStyle2($styleArray, 'fill', 'fillType', $shade);
214
        }
215 10
    }
216
217 10
    private function readStyleRange(SimpleXMLElement $styleAttributes, int $maxCol, int $maxRow): string
218
    {
219 10
        $startColumn = Coordinate::stringFromColumnIndex((int) $styleAttributes['startCol'] + 1);
220 10
        $startRow = $styleAttributes['startRow'] + 1;
221
222 10
        $endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : (int) $styleAttributes['endCol'];
223 10
        $endColumn = Coordinate::stringFromColumnIndex($endColumn + 1);
224
225 10
        $endRow = 1 + (($styleAttributes['endRow'] > $maxRow) ? $maxRow : (int) $styleAttributes['endRow']);
226 10
        $cellRange = $startColumn . $startRow . ':' . $endColumn . $endRow;
227
228 10
        return $cellRange;
229
    }
230
231 10
    private function readStyle(array $styleArray, SimpleXMLElement $styleAttributes, SimpleXMLElement $style): array
232
    {
233 10
        self::addStyle2($styleArray, 'alignment', 'horizontal', (string) $styleAttributes['HAlign']);
234 10
        self::addStyle2($styleArray, 'alignment', 'vertical', (string) $styleAttributes['VAlign']);
235 10
        $styleArray['alignment']['wrapText'] = $styleAttributes['WrapText'] == '1';
236 10
        $styleArray['alignment']['textRotation'] = $this->calcRotation($styleAttributes);
237 10
        $styleArray['alignment']['shrinkToFit'] = $styleAttributes['ShrinkToFit'] == '1';
238 10
        $styleArray['alignment']['indent'] = ((int) ($styleAttributes['Indent']) > 0) ? $styleAttributes['indent'] : 0;
239
240 10
        $this->addColors($styleArray, $styleAttributes);
241
242 10
        $fontAttributes = $style->Style->Font->attributes();
243 10
        if ($fontAttributes !== null) {
244 10
            $styleArray['font']['name'] = (string) $style->Style->Font;
245 10
            $styleArray['font']['size'] = (int) ($fontAttributes['Unit']);
246 10
            $styleArray['font']['bold'] = $fontAttributes['Bold'] == '1';
247 10
            $styleArray['font']['italic'] = $fontAttributes['Italic'] == '1';
248 10
            $styleArray['font']['strikethrough'] = $fontAttributes['StrikeThrough'] == '1';
249 10
            self::addStyle2($styleArray, 'font', 'underline', (string) $fontAttributes['Underline']);
250
251 10
            switch ($fontAttributes['Script']) {
252 10
                case '1':
253 4
                    $styleArray['font']['superscript'] = true;
254
255 4
                    break;
256 10
                case '-1':
257 4
                    $styleArray['font']['subscript'] = true;
258
259 4
                    break;
260
            }
261
        }
262
263 10
        if (isset($style->Style->StyleBorder)) {
264 6
            $srssb = $style->Style->StyleBorder;
265 6
            $this->addBorderStyle($srssb, $styleArray, 'top');
266 6
            $this->addBorderStyle($srssb, $styleArray, 'bottom');
267 6
            $this->addBorderStyle($srssb, $styleArray, 'left');
268 6
            $this->addBorderStyle($srssb, $styleArray, 'right');
269 6
            $this->addBorderDiagonal($srssb, $styleArray);
270
        }
271 10
        if (isset($style->Style->HyperLink)) {
272
            //    TO DO
273 4
            $hyperlink = $style->Style->HyperLink->attributes();
0 ignored issues
show
Unused Code introduced by
The assignment to $hyperlink is dead and can be removed.
Loading history...
274
        }
275
276 10
        return $styleArray;
277
    }
278
}
279