Total Complexity | 141 |
Total Lines | 800 |
Duplicated Lines | 0 % |
Coverage | 74.53% |
Changes | 3 | ||
Bugs | 0 | Features | 0 |
Complex classes like Gnumeric often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Gnumeric, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
25 | class Gnumeric extends BaseReader |
||
26 | { |
||
27 | private const UOM_CONVERSION_POINTS_TO_CENTIMETERS = 0.03527777778; |
||
28 | |||
29 | /** |
||
30 | * Shared Expressions. |
||
31 | * |
||
32 | * @var array |
||
33 | */ |
||
34 | private $expressions = []; |
||
35 | |||
36 | /** |
||
37 | 5 | * Spreadsheet shared across all functions. |
|
38 | * |
||
39 | 5 | * @var Spreadsheet |
|
40 | 5 | */ |
|
41 | 5 | private $spreadsheet; |
|
42 | 5 | ||
43 | private $referenceHelper; |
||
44 | |||
45 | /** |
||
46 | * Namespace shared across all functions. |
||
47 | * It is 'gnm', except for really old sheets which use 'gmr'. |
||
48 | * |
||
49 | * @var string |
||
50 | */ |
||
51 | 4 | private $gnm = 'gnm'; |
|
52 | |||
53 | 4 | /** |
|
54 | * Create a new Gnumeric. |
||
55 | */ |
||
56 | 4 | public function __construct() |
|
57 | { |
||
58 | parent::__construct(); |
||
59 | $this->referenceHelper = ReferenceHelper::getInstance(); |
||
60 | $this->securityScanner = XmlScanner::getInstance($this); |
||
61 | 4 | } |
|
62 | 4 | ||
63 | 4 | /** |
|
64 | * Can the current IReader read the file? |
||
65 | 4 | * |
|
66 | * @param string $pFilename |
||
67 | * |
||
68 | * @return bool |
||
69 | */ |
||
70 | public function canRead($pFilename) |
||
71 | { |
||
72 | File::assertFile($pFilename); |
||
73 | |||
74 | // Check if gzlib functions are available |
||
75 | $data = ''; |
||
76 | if (function_exists('gzread')) { |
||
77 | // Read signature data (first 3 bytes) |
||
78 | $fh = fopen($pFilename, 'rb'); |
||
79 | $data = fread($fh, 2); |
||
1 ignored issue
–
show
|
|||
80 | fclose($fh); |
||
1 ignored issue
–
show
|
|||
81 | } |
||
82 | |||
83 | return $data == chr(0x1F) . chr(0x8B); |
||
84 | } |
||
85 | |||
86 | private static function matchXml(string $name, string $field): bool |
||
87 | { |
||
88 | return 1 === preg_match("/^(gnm|gmr):$field$/", $name); |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * Reads names of the worksheets from a file, without parsing the whole file to a Spreadsheet object. |
||
93 | * |
||
94 | * @param string $pFilename |
||
95 | * |
||
96 | * @return array |
||
97 | */ |
||
98 | public function listWorksheetNames($pFilename) |
||
99 | { |
||
100 | File::assertFile($pFilename); |
||
101 | |||
102 | $xml = new XMLReader(); |
||
103 | $xml->xml($this->securityScanner->scanFile('compress.zlib://' . realpath($pFilename)), null, Settings::getLibXmlLoaderOptions()); |
||
104 | $xml->setParserProperty(2, true); |
||
105 | |||
106 | $worksheetNames = []; |
||
107 | while ($xml->read()) { |
||
108 | if (self::matchXml($xml->name, 'SheetName') && $xml->nodeType == XMLReader::ELEMENT) { |
||
109 | $xml->read(); // Move onto the value node |
||
110 | $worksheetNames[] = (string) $xml->value; |
||
111 | } elseif (self::matchXml($xml->name, 'Sheets')) { |
||
112 | // break out of the loop once we've got our sheet names rather than parse the entire file |
||
113 | break; |
||
114 | } |
||
115 | } |
||
116 | |||
117 | return $worksheetNames; |
||
118 | } |
||
119 | |||
120 | /** |
||
121 | * Return worksheet info (Name, Last Column Letter, Last Column Index, Total Rows, Total Columns). |
||
122 | * |
||
123 | * @param string $pFilename |
||
124 | * |
||
125 | * @return array |
||
126 | */ |
||
127 | public function listWorksheetInfo($pFilename) |
||
128 | { |
||
129 | File::assertFile($pFilename); |
||
130 | |||
131 | $xml = new XMLReader(); |
||
132 | $xml->xml($this->securityScanner->scanFile('compress.zlib://' . realpath($pFilename)), null, Settings::getLibXmlLoaderOptions()); |
||
133 | $xml->setParserProperty(2, true); |
||
134 | |||
135 | $worksheetInfo = []; |
||
136 | while ($xml->read()) { |
||
137 | if (self::matchXml($xml->name, 'Sheet') && $xml->nodeType == XMLReader::ELEMENT) { |
||
138 | $tmpInfo = [ |
||
139 | 'worksheetName' => '', |
||
140 | 'lastColumnLetter' => 'A', |
||
141 | 'lastColumnIndex' => 0, |
||
142 | 'totalRows' => 0, |
||
143 | 'totalColumns' => 0, |
||
144 | ]; |
||
145 | |||
146 | while ($xml->read()) { |
||
147 | if ($xml->nodeType == XMLReader::ELEMENT) { |
||
148 | if (self::matchXml($xml->name, 'Name')) { |
||
149 | $xml->read(); // Move onto the value node |
||
150 | $tmpInfo['worksheetName'] = (string) $xml->value; |
||
151 | 2 | } elseif (self::matchXml($xml->name, 'MaxCol')) { |
|
152 | $xml->read(); // Move onto the value node |
||
153 | 2 | $tmpInfo['lastColumnIndex'] = (int) $xml->value; |
|
154 | 2 | $tmpInfo['totalColumns'] = (int) $xml->value + 1; |
|
155 | 2 | } elseif (self::matchXml($xml->name, 'MaxRow')) { |
|
156 | 2 | $xml->read(); // Move onto the value node |
|
157 | 2 | $tmpInfo['totalRows'] = (int) $xml->value + 1; |
|
158 | |||
159 | 2 | break; |
|
160 | } |
||
161 | } |
||
162 | 2 | } |
|
163 | $tmpInfo['lastColumnLetter'] = Coordinate::stringFromColumnIndex($tmpInfo['lastColumnIndex'] + 1); |
||
164 | $worksheetInfo[] = $tmpInfo; |
||
165 | } |
||
166 | } |
||
167 | |||
168 | return $worksheetInfo; |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | 2 | * @param string $filename |
|
173 | * |
||
174 | * @return string |
||
175 | 2 | */ |
|
176 | private function gzfileGetContents($filename) |
||
177 | { |
||
178 | 2 | $file = @gzopen($filename, 'rb'); |
|
179 | $data = ''; |
||
180 | if ($file !== false) { |
||
181 | while (!gzeof($file)) { |
||
182 | $data .= gzread($file, 1024); |
||
183 | } |
||
184 | gzclose($file); |
||
185 | } |
||
186 | |||
187 | return $data; |
||
188 | } |
||
189 | 2 | ||
190 | private static $mappings = [ |
||
191 | 2 | 'borderStyle' => [ |
|
192 | '0' => Border::BORDER_NONE, |
||
193 | 2 | '1' => Border::BORDER_THIN, |
|
194 | '2' => Border::BORDER_MEDIUM, |
||
195 | 2 | '3' => Border::BORDER_SLANTDASHDOT, |
|
196 | 2 | '4' => Border::BORDER_DASHED, |
|
197 | '5' => Border::BORDER_THICK, |
||
198 | 2 | '6' => Border::BORDER_DOUBLE, |
|
199 | '7' => Border::BORDER_DOTTED, |
||
200 | 2 | '8' => Border::BORDER_MEDIUMDASHED, |
|
201 | '9' => Border::BORDER_DASHDOT, |
||
202 | 2 | '10' => Border::BORDER_MEDIUMDASHDOT, |
|
203 | 2 | '11' => Border::BORDER_DASHDOTDOT, |
|
204 | 2 | '12' => Border::BORDER_MEDIUMDASHDOTDOT, |
|
205 | 2 | '13' => Border::BORDER_MEDIUMDASHDOTDOT, |
|
206 | ], |
||
207 | 2 | 'dataType' => [ |
|
208 | 2 | '10' => DataType::TYPE_NULL, |
|
209 | 2 | '20' => DataType::TYPE_BOOL, |
|
210 | 2 | '30' => DataType::TYPE_NUMERIC, // Integer doesn't exist in Excel |
|
211 | '40' => DataType::TYPE_NUMERIC, // Float |
||
212 | 2 | '50' => DataType::TYPE_ERROR, |
|
213 | 2 | '60' => DataType::TYPE_STRING, |
|
214 | //'70': // Cell Range |
||
215 | 2 | //'80': // Array |
|
216 | 2 | ], |
|
217 | 'fillType' => [ |
||
218 | 2 | '1' => Fill::FILL_SOLID, |
|
219 | 2 | '2' => Fill::FILL_PATTERN_DARKGRAY, |
|
220 | 2 | '3' => Fill::FILL_PATTERN_MEDIUMGRAY, |
|
221 | '4' => Fill::FILL_PATTERN_LIGHTGRAY, |
||
222 | 2 | '5' => Fill::FILL_PATTERN_GRAY125, |
|
223 | 2 | '6' => Fill::FILL_PATTERN_GRAY0625, |
|
224 | 2 | '7' => Fill::FILL_PATTERN_DARKHORIZONTAL, // horizontal stripe |
|
225 | 2 | '8' => Fill::FILL_PATTERN_DARKVERTICAL, // vertical stripe |
|
226 | '9' => Fill::FILL_PATTERN_DARKDOWN, // diagonal stripe |
||
227 | 2 | '10' => Fill::FILL_PATTERN_DARKUP, // reverse diagonal stripe |
|
228 | 2 | '11' => Fill::FILL_PATTERN_DARKGRID, // diagoanl crosshatch |
|
229 | 2 | '12' => Fill::FILL_PATTERN_DARKTRELLIS, // thick diagonal crosshatch |
|
230 | 2 | '13' => Fill::FILL_PATTERN_LIGHTHORIZONTAL, |
|
231 | 2 | '14' => Fill::FILL_PATTERN_LIGHTVERTICAL, |
|
232 | '15' => Fill::FILL_PATTERN_LIGHTUP, |
||
233 | 2 | '16' => Fill::FILL_PATTERN_LIGHTDOWN, |
|
234 | 2 | '17' => Fill::FILL_PATTERN_LIGHTGRID, // thin horizontal crosshatch |
|
235 | 2 | '18' => Fill::FILL_PATTERN_LIGHTTRELLIS, // thin diagonal crosshatch |
|
236 | ], |
||
237 | 2 | 'horizontal' => [ |
|
238 | '1' => Alignment::HORIZONTAL_GENERAL, |
||
239 | '2' => Alignment::HORIZONTAL_LEFT, |
||
240 | 2 | '4' => Alignment::HORIZONTAL_RIGHT, |
|
241 | 2 | '8' => Alignment::HORIZONTAL_CENTER, |
|
242 | 2 | '16' => Alignment::HORIZONTAL_CENTER_CONTINUOUS, |
|
243 | '32' => Alignment::HORIZONTAL_JUSTIFY, |
||
244 | 2 | '64' => Alignment::HORIZONTAL_CENTER_CONTINUOUS, |
|
245 | 2 | ], |
|
246 | 2 | 'underline' => [ |
|
247 | '1' => Font::UNDERLINE_SINGLE, |
||
248 | 2 | '2' => Font::UNDERLINE_DOUBLE, |
|
249 | 2 | '3' => Font::UNDERLINE_SINGLEACCOUNTING, |
|
250 | '4' => Font::UNDERLINE_DOUBLEACCOUNTING, |
||
251 | 2 | ], |
|
252 | 2 | 'vertical' => [ |
|
253 | 2 | '1' => Alignment::VERTICAL_TOP, |
|
254 | 2 | '2' => Alignment::VERTICAL_BOTTOM, |
|
255 | '4' => Alignment::VERTICAL_CENTER, |
||
256 | 2 | '8' => Alignment::VERTICAL_JUSTIFY, |
|
257 | 2 | ], |
|
258 | 2 | ]; |
|
259 | 2 | ||
260 | 2 | public static function gnumericMappings(): array |
|
261 | { |
||
262 | 2 | return self::$mappings; |
|
263 | 2 | } |
|
264 | 2 | ||
265 | private function docPropertiesOld(SimpleXMLElement $gnmXML): void |
||
266 | 2 | { |
|
267 | 2 | $docProps = $this->spreadsheet->getProperties(); |
|
268 | foreach ($gnmXML->Summary->Item as $summaryItem) { |
||
269 | 2 | $propertyName = $summaryItem->name; |
|
270 | 2 | $propertyValue = $summaryItem->{'val-string'}; |
|
271 | 2 | switch ($propertyName) { |
|
272 | case 'title': |
||
273 | 2 | $docProps->setTitle(trim($propertyValue)); |
|
274 | 2 | ||
275 | 2 | break; |
|
276 | case 'comments': |
||
277 | 2 | $docProps->setDescription(trim($propertyValue)); |
|
278 | |||
279 | break; |
||
280 | 2 | case 'keywords': |
|
281 | $docProps->setKeywords(trim($propertyValue)); |
||
282 | |||
283 | break; |
||
284 | case 'category': |
||
285 | $docProps->setCategory(trim($propertyValue)); |
||
286 | |||
287 | break; |
||
288 | case 'manager': |
||
289 | $docProps->setManager(trim($propertyValue)); |
||
290 | |||
291 | break; |
||
292 | case 'author': |
||
293 | $docProps->setCreator(trim($propertyValue)); |
||
294 | $docProps->setLastModifiedBy(trim($propertyValue)); |
||
295 | |||
296 | break; |
||
297 | case 'company': |
||
298 | $docProps->setCompany(trim($propertyValue)); |
||
299 | |||
300 | break; |
||
301 | } |
||
302 | } |
||
303 | } |
||
304 | |||
305 | private function docPropertiesDC(SimpleXMLElement $officePropertyDC): void |
||
306 | { |
||
307 | $docProps = $this->spreadsheet->getProperties(); |
||
308 | foreach ($officePropertyDC as $propertyName => $propertyValue) { |
||
309 | $propertyValue = trim((string) $propertyValue); |
||
310 | switch ($propertyName) { |
||
311 | case 'title': |
||
312 | $docProps->setTitle($propertyValue); |
||
313 | |||
314 | break; |
||
315 | case 'subject': |
||
316 | $docProps->setSubject($propertyValue); |
||
317 | |||
318 | break; |
||
319 | case 'creator': |
||
320 | $docProps->setCreator($propertyValue); |
||
321 | $docProps->setLastModifiedBy($propertyValue); |
||
322 | 2 | ||
323 | 2 | break; |
|
324 | 2 | case 'date': |
|
325 | 2 | $creationDate = strtotime($propertyValue); |
|
326 | $docProps->setCreated($creationDate); |
||
327 | $docProps->setModified($creationDate); |
||
328 | |||
329 | 2 | break; |
|
330 | case 'description': |
||
331 | $docProps->setDescription($propertyValue); |
||
332 | 2 | ||
333 | 2 | break; |
|
334 | } |
||
335 | } |
||
336 | } |
||
337 | 2 | ||
338 | private function docPropertiesMeta(SimpleXMLElement $officePropertyMeta, array $namespacesMeta): void |
||
339 | 2 | { |
|
340 | 2 | $docProps = $this->spreadsheet->getProperties(); |
|
341 | 2 | foreach ($officePropertyMeta as $propertyName => $propertyValue) { |
|
342 | 2 | $attributes = $propertyValue->attributes($namespacesMeta['meta']); |
|
343 | 2 | $propertyValue = trim((string) $propertyValue); |
|
344 | 2 | switch ($propertyName) { |
|
345 | 2 | case 'keyword': |
|
346 | 2 | $docProps->setKeywords($propertyValue); |
|
347 | |||
348 | 2 | break; |
|
349 | case 'initial-creator': |
||
350 | $docProps->setCreator($propertyValue); |
||
351 | 2 | $docProps->setLastModifiedBy($propertyValue); |
|
352 | 2 | ||
353 | break; |
||
354 | 2 | case 'creation-date': |
|
355 | 2 | $creationDate = strtotime($propertyValue); |
|
356 | 2 | $docProps->setCreated($creationDate); |
|
357 | $docProps->setModified($creationDate); |
||
358 | 2 | ||
359 | 2 | break; |
|
360 | 2 | case 'user-defined': |
|
361 | [, $attrName] = explode(':', $attributes['name']); |
||
362 | 2 | switch ($attrName) { |
|
363 | 2 | case 'publisher': |
|
364 | 2 | $docProps->setCompany($propertyValue); |
|
365 | |||
366 | 2 | break; |
|
367 | 2 | case 'category': |
|
368 | 2 | $docProps->setCategory($propertyValue); |
|
369 | |||
370 | 2 | break; |
|
371 | 2 | case 'manager': |
|
372 | 2 | $docProps->setManager($propertyValue); |
|
373 | |||
374 | 2 | break; |
|
375 | } |
||
376 | |||
377 | break; |
||
378 | } |
||
379 | } |
||
380 | 2 | } |
|
381 | 2 | ||
382 | 2 | private function docProperties(SimpleXMLElement $xml, SimpleXMLElement $gnmXML, array $namespacesMeta): void |
|
383 | 2 | { |
|
384 | if (isset($namespacesMeta['office'])) { |
||
385 | 2 | $officeXML = $xml->children($namespacesMeta['office']); |
|
386 | 2 | $officeDocXML = $officeXML->{'document-meta'}; |
|
387 | $officeDocMetaXML = $officeDocXML->meta; |
||
388 | 2 | ||
389 | 2 | foreach ($officeDocMetaXML as $officePropertyData) { |
|
390 | $officePropertyDC = []; |
||
391 | if (isset($namespacesMeta['dc'])) { |
||
392 | 2 | $officePropertyDC = $officePropertyData->children($namespacesMeta['dc']); |
|
393 | } |
||
394 | $this->docPropertiesDC($officePropertyDC); |
||
395 | 2 | ||
396 | 2 | $officePropertyMeta = []; |
|
397 | if (isset($namespacesMeta['meta'])) { |
||
398 | $officePropertyMeta = $officePropertyData->children($namespacesMeta['meta']); |
||
399 | } |
||
400 | $this->docPropertiesMeta($officePropertyMeta, $namespacesMeta); |
||
401 | 2 | } |
|
402 | 2 | } elseif (isset($gnmXML->Summary)) { |
|
403 | 2 | $this->docPropertiesOld($gnmXML); |
|
404 | 2 | } |
|
405 | 2 | } |
|
406 | 2 | ||
407 | 2 | private function processComments(SimpleXMLElement $sheet): void |
|
408 | 2 | { |
|
409 | 2 | if ((!$this->readDataOnly) && (isset($sheet->Objects))) { |
|
410 | foreach ($sheet->Objects->children($this->gnm, true) as $key => $comment) { |
||
411 | $commentAttributes = $comment->attributes(); |
||
412 | 2 | // Only comment objects are handled at the moment |
|
413 | if ($commentAttributes->Text) { |
||
414 | 2 | $this->spreadsheet->getActiveSheet()->getComment((string) $commentAttributes->ObjectBound)->setAuthor((string) $commentAttributes->Author)->setText($this->parseRichText((string) $commentAttributes->Text)); |
|
415 | 2 | } |
|
416 | 2 | } |
|
417 | 2 | } |
|
418 | 2 | } |
|
419 | |||
420 | /** |
||
421 | * Loads Spreadsheet from file. |
||
422 | 2 | * |
|
423 | * @param string $pFilename |
||
424 | * |
||
425 | 2 | * @return Spreadsheet |
|
426 | */ |
||
427 | public function load($pFilename) |
||
428 | { |
||
429 | 2 | // Create new Spreadsheet |
|
430 | 2 | $spreadsheet = new Spreadsheet(); |
|
431 | 2 | $spreadsheet->removeSheetByIndex(0); |
|
432 | |||
433 | 2 | // Load into this instance |
|
434 | 2 | return $this->loadIntoExisting($pFilename, $spreadsheet); |
|
435 | } |
||
436 | |||
437 | /** |
||
438 | 2 | * Loads from file into Spreadsheet instance. |
|
439 | 2 | */ |
|
440 | public function loadIntoExisting(string $pFilename, Spreadsheet $spreadsheet): Spreadsheet |
||
615 | } |
||
616 | 2 | ||
617 | private function addBorderDiagonal(SimpleXMLElement $srssb, array &$styleArray): void |
||
618 | { |
||
619 | if (isset($srssb->Diagonal, $srssb->{'Rev-Diagonal'})) { |
||
620 | 2 | $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->Diagonal->attributes()); |
|
621 | $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_BOTH; |
||
622 | } elseif (isset($srssb->Diagonal)) { |
||
623 | $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->Diagonal->attributes()); |
||
624 | 2 | $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_UP; |
|
625 | } elseif (isset($srssb->{'Rev-Diagonal'})) { |
||
626 | $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->{'Rev-Diagonal'}->attributes()); |
||
627 | $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_DOWN; |
||
628 | } |
||
629 | } |
||
630 | |||
631 | 2 | private function addBorderStyle(SimpleXMLElement $srssb, array &$styleArray, string $direction): void |
|
632 | 2 | { |
|
633 | 2 | $ucDirection = ucfirst($direction); |
|
634 | 2 | if (isset($srssb->$ucDirection)) { |
|
635 | 2 | $styleArray['borders'][$direction] = self::parseBorderAttributes($srssb->$ucDirection->attributes()); |
|
636 | 2 | } |
|
637 | 2 | } |
|
638 | 2 | ||
639 | 2 | private function processMergedCells(SimpleXMLElement $sheet): void |
|
640 | { |
||
641 | 2 | // Handle Merged Cells in this worksheet |
|
642 | 2 | if (isset($sheet->MergedRegions)) { |
|
643 | 2 | foreach ($sheet->MergedRegions->Merge as $mergeCells) { |
|
644 | if (strpos($mergeCells, ':') !== false) { |
||
645 | 2 | $this->spreadsheet->getActiveSheet()->mergeCells($mergeCells); |
|
646 | 2 | } |
|
647 | 2 | } |
|
648 | } |
||
649 | 2 | } |
|
650 | 2 | ||
651 | 2 | private function processColumnLoop(int $c, int $maxCol, SimpleXMLElement $columnOverride, float $defaultWidth): int |
|
652 | { |
||
653 | 2 | $columnAttributes = $columnOverride->attributes(); |
|
654 | $column = $columnAttributes['No']; |
||
655 | 2 | $columnWidth = ((float) $columnAttributes['Unit']) / 5.4; |
|
656 | $hidden = (isset($columnAttributes['Hidden'])) && ((string) $columnAttributes['Hidden'] == '1'); |
||
657 | 2 | $columnCount = (isset($columnAttributes['Count'])) ? $columnAttributes['Count'] : 1; |
|
658 | while ($c < $column) { |
||
659 | 2 | $this->spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setWidth($defaultWidth); |
|
660 | 2 | ++$c; |
|
661 | 2 | } |
|
662 | while (($c < ($column + $columnCount)) && ($c <= $maxCol)) { |
||
663 | 2 | $this->spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setWidth($columnWidth); |
|
664 | 2 | if ($hidden) { |
|
665 | 2 | $this->spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setVisible(false); |
|
666 | } |
||
667 | 2 | ++$c; |
|
668 | } |
||
669 | |||
670 | 2 | return $c; |
|
671 | 2 | } |
|
672 | 2 | ||
673 | private function processColumnWidths(SimpleXMLElement $sheet, int $maxCol): void |
||
674 | 2 | { |
|
675 | 2 | if ((!$this->readDataOnly) && (isset($sheet->Cols))) { |
|
676 | // Column Widths |
||
677 | 2 | $columnAttributes = $sheet->Cols->attributes(); |
|
678 | 2 | $defaultWidth = $columnAttributes['DefaultSizePts'] / 5.4; |
|
679 | $c = 0; |
||
680 | 2 | foreach ($sheet->Cols->ColInfo as $columnOverride) { |
|
681 | 2 | $c = $this->processColumnLoop($c, $maxCol, $columnOverride, $defaultWidth); |
|
682 | } |
||
683 | 2 | while ($c <= $maxCol) { |
|
684 | 2 | $this->spreadsheet->getActiveSheet()->getColumnDimension(Coordinate::stringFromColumnIndex($c + 1))->setWidth($defaultWidth); |
|
685 | 2 | ++$c; |
|
686 | 2 | } |
|
687 | 2 | } |
|
688 | 2 | } |
|
689 | 2 | ||
690 | 2 | private function processRowLoop(int $r, int $maxRow, SimpleXMLElement $rowOverride, float $defaultHeight): int |
|
691 | 2 | { |
|
692 | $rowAttributes = $rowOverride->attributes(); |
||
693 | $row = $rowAttributes['No']; |
||
694 | 2 | $rowHeight = (float) $rowAttributes['Unit']; |
|
695 | $hidden = (isset($rowAttributes['Hidden'])) && ((string) $rowAttributes['Hidden'] == '1'); |
||
696 | 2 | $rowCount = (isset($rowAttributes['Count'])) ? $rowAttributes['Count'] : 1; |
|
697 | while ($r < $row) { |
||
698 | ++$r; |
||
699 | 2 | $this->spreadsheet->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight); |
|
700 | } |
||
701 | while (($r < ($row + $rowCount)) && ($r < $maxRow)) { |
||
702 | ++$r; |
||
703 | $this->spreadsheet->getActiveSheet()->getRowDimension($r)->setRowHeight($rowHeight); |
||
704 | 2 | if ($hidden) { |
|
705 | $this->spreadsheet->getActiveSheet()->getRowDimension($r)->setVisible(false); |
||
706 | 2 | } |
|
707 | 2 | } |
|
708 | 2 | ||
709 | 2 | return $r; |
|
710 | 2 | } |
|
711 | 2 | ||
712 | 2 | private function processRowHeights(SimpleXMLElement $sheet, int $maxRow): void |
|
713 | 2 | { |
|
714 | 2 | if ((!$this->readDataOnly) && (isset($sheet->Rows))) { |
|
715 | 2 | // Row Heights |
|
716 | 2 | $rowAttributes = $sheet->Rows->attributes(); |
|
717 | 2 | $defaultHeight = (float) $rowAttributes['DefaultSizePts']; |
|
718 | $r = 0; |
||
719 | 2 | ||
720 | 2 | foreach ($sheet->Rows->RowInfo as $rowOverride) { |
|
721 | 2 | $r = $this->processRowLoop($r, $maxRow, $rowOverride, $defaultHeight); |
|
722 | 2 | } |
|
723 | // never executed, I can't figure out any circumstances |
||
724 | 2 | // under which it would be executed, and, even if |
|
725 | // such exist, I'm not convinced this is needed. |
||
726 | //while ($r < $maxRow) { |
||
727 | 2 | // ++$r; |
|
728 | // $this->spreadsheet->getActiveSheet()->getRowDimension($r)->setRowHeight($defaultHeight); |
||
729 | //} |
||
730 | } |
||
731 | } |
||
732 | |||
733 | 2 | private function processDefinedNames(SimpleXMLElement $gnmXML): void |
|
734 | { |
||
735 | 2 | // Loop through definedNames (global named ranges) |
|
736 | 2 | if (isset($gnmXML->Names)) { |
|
737 | 2 | foreach ($gnmXML->Names->Name as $namedRange) { |
|
738 | $name = (string) $namedRange->name; |
||
739 | 2 | $range = (string) $namedRange->value; |
|
740 | 2 | if (stripos($range, '#REF!') !== false) { |
|
741 | 2 | continue; |
|
742 | 2 | } |
|
743 | 2 | ||
744 | 2 | $range = Worksheet::extractSheetTitle($range, true); |
|
745 | 2 | $range[0] = trim($range[0], "'"); |
|
746 | 2 | if ($worksheet = $this->spreadsheet->getSheetByName($range[0])) { |
|
747 | 2 | $extractedRange = str_replace('$', '', $range[1]); |
|
748 | $this->spreadsheet->addNamedRange(new NamedRange($name, $worksheet, $extractedRange)); |
||
749 | 2 | } |
|
750 | 2 | } |
|
751 | 2 | } |
|
752 | 2 | } |
|
753 | |||
754 | private function calcRotation(SimpleXMLElement $styleAttributes): int |
||
755 | { |
||
756 | $rotation = (int) $styleAttributes->Rotation; |
||
757 | 2 | if ($rotation >= 270 && $rotation <= 360) { |
|
758 | $rotation -= 360; |
||
759 | } |
||
760 | $rotation = (abs($rotation) > 90) ? 0 : $rotation; |
||
761 | |||
762 | return $rotation; |
||
763 | } |
||
764 | 2 | ||
765 | 2 | private static function addStyle(array &$styleArray, string $key, string $value): void |
|
766 | 2 | { |
|
767 | 2 | if (array_key_exists($value, self::$mappings[$key])) { |
|
768 | $styleArray[$key] = self::$mappings[$key][$value]; |
||
769 | } |
||
770 | } |
||
771 | |||
772 | 2 | private static function addStyle2(array &$styleArray, string $key1, string $key, string $value): void |
|
773 | { |
||
774 | if (array_key_exists($value, self::$mappings[$key])) { |
||
775 | $styleArray[$key1][$key] = self::$mappings[$key][$value]; |
||
776 | 2 | } |
|
777 | 2 | } |
|
778 | 2 | ||
779 | 2 | private static function parseBorderAttributes($borderAttributes) |
|
789 | } |
||
790 | |||
791 | private function parseRichText($is) |
||
792 | { |
||
793 | $value = new RichText(); |
||
794 | 2 | $value->createText($is); |
|
795 | |||
796 | return $value; |
||
797 | 2 | } |
|
798 | |||
799 | 2 | private static function parseGnumericColour($gnmColour) |
|
800 | 2 | { |
|
801 | 2 | [$gnmR, $gnmG, $gnmB] = explode(':', $gnmColour); |
|
802 | $gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2); |
||
803 | $gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2); |
||
804 | 2 | $gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2); |
|
805 | 2 | ||
806 | return $gnmR . $gnmG . $gnmB; |
||
807 | } |
||
808 | |||
809 | 2 | private function addColors(array &$styleArray, SimpleXMLElement $styleAttributes): void |
|
825 | 2 | } |
|
826 | 2 | } |
|
827 | } |
||
828 |