Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Chart 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 Chart, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
29 | class Chart |
||
30 | { |
||
31 | /** |
||
32 | * @param \SimpleXMLElement $component |
||
33 | * @param string $name |
||
34 | * @param string $format |
||
35 | */ |
||
36 | 1 | private static function getAttribute(\SimpleXMLElement $component, $name, $format) |
|
37 | { |
||
38 | 1 | $attributes = $component->attributes(); |
|
39 | 1 | if (isset($attributes[$name])) { |
|
40 | 1 | if ($format == 'string') { |
|
41 | 1 | return (string) $attributes[$name]; |
|
42 | 1 | } elseif ($format == 'integer') { |
|
43 | 1 | return (int) $attributes[$name]; |
|
44 | 1 | } elseif ($format == 'boolean') { |
|
45 | 1 | return (bool) ($attributes[$name] === '0' || $attributes[$name] !== 'true') ? false : true; |
|
46 | } |
||
47 | |||
48 | return (float) $attributes[$name]; |
||
49 | } |
||
50 | |||
51 | 1 | return null; |
|
52 | } |
||
53 | |||
54 | private static function readColor($color, $background = false) |
||
55 | { |
||
56 | if (isset($color['rgb'])) { |
||
57 | return (string) $color['rgb']; |
||
58 | } elseif (isset($color['indexed'])) { |
||
59 | return \PhpOffice\PhpSpreadsheet\Style\Color::indexedColor($color['indexed'] - 7, $background)->getARGB(); |
||
60 | } |
||
61 | } |
||
62 | |||
63 | /** |
||
64 | * @param \SimpleXMLElement $chartElements |
||
65 | * @param string $chartName |
||
66 | */ |
||
67 | 1 | public static function readChart(\SimpleXMLElement $chartElements, $chartName) |
|
208 | |||
209 | 1 | private static function chartTitle(\SimpleXMLElement $titleDetails, array $namespacesChartMeta) |
|
210 | { |
||
211 | 1 | $caption = []; |
|
212 | 1 | $titleLayout = null; |
|
213 | 1 | foreach ($titleDetails as $titleDetailKey => $chartDetail) { |
|
214 | switch ($titleDetailKey) { |
||
215 | 1 | case 'tx': |
|
216 | 1 | $titleDetails = $chartDetail->rich->children($namespacesChartMeta['a']); |
|
217 | 1 | foreach ($titleDetails as $titleKey => $titleDetail) { |
|
218 | switch ($titleKey) { |
||
219 | 1 | case 'p': |
|
220 | 1 | $titleDetailPart = $titleDetail->children($namespacesChartMeta['a']); |
|
221 | 1 | $caption[] = self::parseRichText($titleDetailPart); |
|
222 | } |
||
223 | } |
||
224 | 1 | break; |
|
225 | 1 | case 'layout': |
|
226 | 1 | $titleLayout = self::chartLayoutDetails($chartDetail, $namespacesChartMeta); |
|
227 | 1 | break; |
|
228 | } |
||
229 | } |
||
230 | |||
231 | 1 | return new \PhpOffice\PhpSpreadsheet\Chart\Title($caption, $titleLayout); |
|
232 | } |
||
233 | |||
234 | 1 | private static function chartLayoutDetails($chartDetail, $namespacesChartMeta) |
|
250 | |||
251 | 1 | private static function chartDataSeries($chartDetail, $namespacesChartMeta, $plotType) |
|
302 | |||
303 | 1 | private static function chartDataSeriesValueSet($seriesDetail, $namespacesChartMeta, $marker = null, $smoothLine = false) |
|
331 | |||
332 | 1 | private static function chartDataSeriesValues($seriesValueSet, $dataType = 'n') |
|
333 | { |
||
334 | 1 | $seriesVal = []; |
|
335 | 1 | $formatCode = ''; |
|
336 | 1 | $pointCount = 0; |
|
337 | |||
338 | 1 | View Code Duplication | foreach ($seriesValueSet as $seriesValueIdx => $seriesValue) { |
339 | switch ($seriesValueIdx) { |
||
340 | 1 | case 'ptCount': |
|
341 | 1 | $pointCount = self::getAttribute($seriesValue, 'val', 'integer'); |
|
342 | 1 | break; |
|
343 | 1 | case 'formatCode': |
|
344 | 1 | $formatCode = (string) $seriesValue; |
|
345 | 1 | break; |
|
346 | 1 | case 'pt': |
|
347 | 1 | $pointVal = self::getAttribute($seriesValue, 'idx', 'integer'); |
|
348 | 1 | if ($dataType == 's') { |
|
349 | 1 | $seriesVal[$pointVal] = (string) $seriesValue->v; |
|
350 | 1 | } elseif ($seriesValue->v === Functions::NA()) { |
|
351 | $seriesVal[$pointVal] = null; |
||
352 | } else { |
||
353 | 1 | $seriesVal[$pointVal] = (float) $seriesValue->v; |
|
354 | } |
||
355 | 1 | break; |
|
356 | } |
||
357 | } |
||
358 | |||
359 | return [ |
||
360 | 1 | 'formatCode' => $formatCode, |
|
361 | 1 | 'pointCount' => $pointCount, |
|
362 | 1 | 'dataValues' => $seriesVal, |
|
363 | ]; |
||
364 | } |
||
365 | |||
366 | 1 | private static function chartDataSeriesValuesMultiLevel($seriesValueSet, $dataType = 'n') |
|
367 | { |
||
368 | 1 | $seriesVal = []; |
|
369 | 1 | $formatCode = ''; |
|
370 | 1 | $pointCount = 0; |
|
371 | |||
372 | 1 | foreach ($seriesValueSet->lvl as $seriesLevelIdx => $seriesLevel) { |
|
373 | 1 | View Code Duplication | foreach ($seriesLevel as $seriesValueIdx => $seriesValue) { |
374 | switch ($seriesValueIdx) { |
||
375 | 1 | case 'ptCount': |
|
376 | $pointCount = self::getAttribute($seriesValue, 'val', 'integer'); |
||
377 | break; |
||
378 | 1 | case 'formatCode': |
|
379 | $formatCode = (string) $seriesValue; |
||
380 | break; |
||
381 | 1 | case 'pt': |
|
382 | 1 | $pointVal = self::getAttribute($seriesValue, 'idx', 'integer'); |
|
383 | 1 | if ($dataType == 's') { |
|
384 | 1 | $seriesVal[$pointVal][] = (string) $seriesValue->v; |
|
385 | } elseif ($seriesValue->v === Functions::NA()) { |
||
386 | $seriesVal[$pointVal] = null; |
||
387 | } else { |
||
388 | $seriesVal[$pointVal][] = (float) $seriesValue->v; |
||
389 | } |
||
390 | 1 | break; |
|
391 | } |
||
392 | } |
||
393 | } |
||
394 | |||
395 | return [ |
||
396 | 1 | 'formatCode' => $formatCode, |
|
397 | 1 | 'pointCount' => $pointCount, |
|
398 | 1 | 'dataValues' => $seriesVal, |
|
399 | ]; |
||
400 | } |
||
401 | |||
402 | 1 | private static function parseRichText(\SimpleXMLElement $titleDetailPart) |
|
403 | { |
||
404 | 1 | $value = new \PhpOffice\PhpSpreadsheet\RichText(); |
|
405 | |||
406 | 1 | foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) { |
|
407 | 1 | if (isset($titleDetailElement->t)) { |
|
408 | 1 | $objText = $value->createTextRun((string) $titleDetailElement->t); |
|
409 | } |
||
410 | 1 | if (isset($titleDetailElement->rPr)) { |
|
411 | 1 | View Code Duplication | if (isset($titleDetailElement->rPr->rFont['val'])) { |
412 | $objText->getFont()->setName((string) $titleDetailElement->rPr->rFont['val']); |
||
413 | } |
||
414 | |||
415 | 1 | $fontSize = (self::getAttribute($titleDetailElement->rPr, 'sz', 'integer')); |
|
416 | 1 | if (!is_null($fontSize)) { |
|
417 | 1 | $objText->getFont()->setSize(floor($fontSize / 100)); |
|
418 | } |
||
419 | |||
420 | 1 | $fontColor = (self::getAttribute($titleDetailElement->rPr, 'color', 'string')); |
|
421 | 1 | if (!is_null($fontColor)) { |
|
422 | $objText->getFont()->setColor(new \PhpOffice\PhpSpreadsheet\Style\Color(self::readColor($fontColor))); |
||
423 | } |
||
424 | |||
425 | 1 | $bold = self::getAttribute($titleDetailElement->rPr, 'b', 'boolean'); |
|
426 | 1 | if (!is_null($bold)) { |
|
427 | 1 | $objText->getFont()->setBold($bold); |
|
428 | } |
||
429 | |||
430 | 1 | $italic = self::getAttribute($titleDetailElement->rPr, 'i', 'boolean'); |
|
431 | 1 | if (!is_null($italic)) { |
|
432 | 1 | $objText->getFont()->setItalic($italic); |
|
433 | } |
||
434 | |||
435 | 1 | $baseline = self::getAttribute($titleDetailElement->rPr, 'baseline', 'integer'); |
|
436 | 1 | if (!is_null($baseline)) { |
|
437 | 1 | if ($baseline > 0) { |
|
438 | 1 | $objText->getFont()->setSuperScript(true); |
|
439 | 1 | } elseif ($baseline < 0) { |
|
440 | 1 | $objText->getFont()->setSubScript(true); |
|
441 | } |
||
442 | } |
||
443 | |||
444 | 1 | $underscore = (self::getAttribute($titleDetailElement->rPr, 'u', 'string')); |
|
445 | 1 | if (!is_null($underscore)) { |
|
446 | 1 | if ($underscore == 'sng') { |
|
447 | 1 | $objText->getFont()->setUnderline(\PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_SINGLE); |
|
448 | 1 | } elseif ($underscore == 'dbl') { |
|
449 | 1 | $objText->getFont()->setUnderline(\PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_DOUBLE); |
|
450 | } else { |
||
451 | 1 | $objText->getFont()->setUnderline(\PhpOffice\PhpSpreadsheet\Style\Font::UNDERLINE_NONE); |
|
452 | } |
||
453 | } |
||
454 | |||
455 | 1 | $strikethrough = (self::getAttribute($titleDetailElement->rPr, 's', 'string')); |
|
456 | 1 | if (!is_null($strikethrough)) { |
|
457 | if ($strikethrough == 'noStrike') { |
||
458 | $objText->getFont()->setStrikethrough(false); |
||
459 | } else { |
||
460 | $objText->getFont()->setStrikethrough(true); |
||
461 | } |
||
462 | } |
||
463 | } |
||
464 | } |
||
465 | |||
466 | 1 | return $value; |
|
467 | } |
||
468 | |||
469 | 1 | private static function readChartAttributes($chartDetail) |
|
498 | |||
499 | /** |
||
500 | * @param \PhpOffice\PhpSpreadsheet\Chart\Layout $plotArea |
||
501 | * @param mixed $plotAttributes |
||
502 | */ |
||
503 | 1 | private static function setChartAttributes(\PhpOffice\PhpSpreadsheet\Chart\Layout $plotArea, $plotAttributes) |
|
531 | } |
||
532 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.