Complex classes like PowerPoint2007 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 PowerPoint2007, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 39 | class PowerPoint2007 implements ReaderInterface |
||
| 40 | { |
||
| 41 | /** |
||
| 42 | * Output Object |
||
| 43 | * @var PhpPresentation |
||
| 44 | */ |
||
| 45 | protected $oPhpPresentation; |
||
| 46 | /** |
||
| 47 | * Output Object |
||
| 48 | * @var \ZipArchive |
||
| 49 | */ |
||
| 50 | protected $oZip; |
||
| 51 | /** |
||
| 52 | * @var array[] |
||
| 53 | */ |
||
| 54 | protected $arrayRels = array(); |
||
| 55 | /** |
||
| 56 | * @var SlideLayout[] |
||
| 57 | */ |
||
| 58 | protected $arraySlideLayouts = array(); |
||
| 59 | /* |
||
| 60 | * @var string |
||
| 61 | */ |
||
| 62 | protected $filename; |
||
| 63 | |||
| 64 | /** |
||
| 65 | * Can the current \PhpOffice\PhpPresentation\Reader\ReaderInterface read the file? |
||
| 66 | * |
||
| 67 | * @param string $pFilename |
||
| 68 | * @throws \Exception |
||
| 69 | * @return boolean |
||
| 70 | */ |
||
| 71 | 2 | public function canRead($pFilename) |
|
| 75 | |||
| 76 | /** |
||
| 77 | * Does a file support UnserializePhpPresentation ? |
||
| 78 | * |
||
| 79 | * @param string $pFilename |
||
| 80 | * @throws \Exception |
||
| 81 | * @return boolean |
||
| 82 | */ |
||
| 83 | 9 | public function fileSupportsUnserializePhpPresentation($pFilename = '') |
|
| 84 | { |
||
| 85 | // Check if file exists |
||
| 86 | 9 | if (!file_exists($pFilename)) { |
|
| 87 | 2 | throw new \Exception("Could not open " . $pFilename . " for reading! File does not exist."); |
|
| 88 | } |
||
| 89 | |||
| 90 | 7 | $oZip = new ZipArchive(); |
|
| 91 | // Is it a zip ? |
||
| 92 | 7 | if ($oZip->open($pFilename) === true) { |
|
| 93 | // Is it an OpenXML Document ? |
||
| 94 | // Is it a Presentation ? |
||
| 95 | 5 | if (is_array($oZip->statName('[Content_Types].xml')) && is_array($oZip->statName('ppt/presentation.xml'))) { |
|
| 96 | 5 | return true; |
|
| 97 | } |
||
| 98 | } |
||
| 99 | 3 | return false; |
|
| 100 | } |
||
| 101 | |||
| 102 | /** |
||
| 103 | * Loads PhpPresentation Serialized file |
||
| 104 | * |
||
| 105 | * @param string $pFilename |
||
| 106 | * @return \PhpOffice\PhpPresentation\PhpPresentation |
||
| 107 | * @throws \Exception |
||
| 108 | */ |
||
| 109 | 6 | public function load($pFilename) |
|
| 118 | |||
| 119 | /** |
||
| 120 | * Load PhpPresentation Serialized file |
||
| 121 | * |
||
| 122 | * @param string $pFilename |
||
| 123 | * @return \PhpOffice\PhpPresentation\PhpPresentation |
||
| 124 | */ |
||
| 125 | 4 | protected function loadFile($pFilename) |
|
| 156 | |||
| 157 | /** |
||
| 158 | * Read Document Properties |
||
| 159 | * @param string $sPart |
||
| 160 | */ |
||
| 161 | 4 | protected function loadDocumentProperties($sPart) |
|
| 190 | |||
| 191 | /** |
||
| 192 | * Read Custom Properties |
||
| 193 | * @param string $sPart |
||
| 194 | */ |
||
| 195 | 1 | protected function loadCustomProperties($sPart) |
|
| 208 | |||
| 209 | /** |
||
| 210 | * Read View Properties |
||
| 211 | * @param string $sPart |
||
| 212 | */ |
||
| 213 | 4 | protected function loadViewProperties($sPart) |
|
| 225 | |||
| 226 | /** |
||
| 227 | * Extract all slides |
||
| 228 | */ |
||
| 229 | 4 | protected function loadSlides($sPart) |
|
| 251 | |||
| 252 | /** |
||
| 253 | * Extract all MasterSlides |
||
| 254 | * @param XMLReader $xmlReader |
||
| 255 | * @param $fileRels |
||
| 256 | */ |
||
| 257 | 4 | protected function loadMasterSlides(XMLReader $xmlReader, $fileRels) |
|
| 274 | |||
| 275 | /** |
||
| 276 | * Extract data from slide |
||
| 277 | * @param string $sPart |
||
| 278 | * @param string $baseFile |
||
| 279 | */ |
||
| 280 | 4 | protected function loadSlide($sPart, $baseFile) |
|
| 281 | { |
||
| 282 | 4 | $xmlReader = new XMLReader(); |
|
| 283 | 4 | if ($xmlReader->getDomFromString($sPart)) { |
|
| 284 | // Core |
||
| 285 | 4 | $oSlide = $this->oPhpPresentation->createSlide(); |
|
| 286 | 4 | $this->oPhpPresentation->setActiveSlideIndex($this->oPhpPresentation->getSlideCount() - 1); |
|
| 287 | 4 | $oSlide->setRelsIndex('ppt/slides/_rels/' . $baseFile . '.rels'); |
|
| 288 | |||
| 289 | // Background |
||
| 290 | 4 | $oElement = $xmlReader->getElement('/p:sld/p:cSld/p:bg/p:bgPr'); |
|
| 291 | 4 | if ($oElement) { |
|
| 292 | $oElementColor = $xmlReader->getElement('a:solidFill/a:srgbClr', $oElement); |
||
| 293 | if ($oElementColor) { |
||
| 294 | // Color |
||
| 295 | $oColor = new Color(); |
||
| 296 | $oColor->setRGB($oElementColor->hasAttribute('val') ? $oElementColor->getAttribute('val') : null); |
||
| 297 | // Background |
||
| 298 | $oBackground = new \PhpOffice\PhpPresentation\Slide\Background\Color(); |
||
| 299 | $oBackground->setColor($oColor); |
||
| 300 | // Slide Background |
||
| 301 | $oSlide = $this->oPhpPresentation->getActiveSlide(); |
||
| 302 | $oSlide->setBackground($oBackground); |
||
| 303 | } |
||
| 304 | $oElementImage = $xmlReader->getElement('a:blipFill/a:blip', $oElement); |
||
| 305 | if ($oElementImage) { |
||
| 306 | $relImg = $this->arrayRels['ppt/slides/_rels/' . $baseFile . '.rels'][$oElementImage->getAttribute('r:embed')]; |
||
| 307 | if (is_array($relImg)) { |
||
| 308 | // File |
||
| 309 | $pathImage = 'ppt/slides/' . $relImg['Target']; |
||
| 310 | $pathImage = explode('/', $pathImage); |
||
| 311 | foreach ($pathImage as $key => $partPath) { |
||
| 312 | if ($partPath == '..') { |
||
| 313 | unset($pathImage[$key - 1]); |
||
| 314 | unset($pathImage[$key]); |
||
| 315 | } |
||
| 316 | } |
||
| 317 | $pathImage = implode('/', $pathImage); |
||
| 318 | $contentImg = $this->oZip->getFromName($pathImage); |
||
| 319 | |||
| 320 | $tmpBkgImg = tempnam(sys_get_temp_dir(), 'PhpPresentationReaderPpt2007Bkg'); |
||
| 321 | file_put_contents($tmpBkgImg, $contentImg); |
||
| 322 | // Background |
||
| 323 | $oBackground = new Image(); |
||
| 324 | $oBackground->setPath($tmpBkgImg); |
||
| 325 | // Slide Background |
||
| 326 | $oSlide = $this->oPhpPresentation->getActiveSlide(); |
||
| 327 | $oSlide->setBackground($oBackground); |
||
| 328 | } |
||
| 329 | } |
||
| 330 | } |
||
| 331 | |||
| 332 | // Shapes |
||
| 333 | 4 | foreach ($xmlReader->getElements('/p:sld/p:cSld/p:spTree/*') as $oNode) { |
|
| 334 | 4 | switch ($oNode->tagName) { |
|
| 335 | 4 | case 'p:pic': |
|
| 336 | 3 | $this->loadShapeDrawing($xmlReader, $oNode, $oSlide); |
|
| 337 | 3 | break; |
|
| 338 | 4 | case 'p:sp': |
|
| 339 | 4 | $this->loadShapeRichText($xmlReader, $oNode, $oSlide); |
|
| 340 | 4 | break; |
|
| 341 | 4 | default: |
|
| 342 | //var_export($oNode->tagName); |
||
| 343 | } |
||
| 344 | } |
||
| 345 | // Layout |
||
| 346 | 4 | $oSlide = $this->oPhpPresentation->getActiveSlide(); |
|
| 347 | 4 | foreach ($this->arrayRels['ppt/slides/_rels/' . $baseFile . '.rels'] as $valueRel) { |
|
| 348 | 4 | if ($valueRel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout') { |
|
| 349 | 4 | $layoutBasename = basename($valueRel['Target']); |
|
| 350 | 4 | if (array_key_exists($layoutBasename, $this->arraySlideLayouts)) { |
|
| 351 | 4 | $oSlide->setSlideLayout($this->arraySlideLayouts[$layoutBasename]); |
|
| 352 | } |
||
| 353 | 4 | break; |
|
| 354 | } |
||
| 355 | } |
||
| 356 | } |
||
| 357 | 4 | } |
|
| 358 | |||
| 359 | 4 | private function loadMasterSlide($sPart, $baseFile) |
|
| 360 | { |
||
| 361 | 4 | $xmlReader = new XMLReader(); |
|
| 362 | 4 | if ($xmlReader->getDomFromString($sPart)) { |
|
| 363 | // Core |
||
| 364 | 4 | $oSlideMaster = $this->oPhpPresentation->createMasterSlide(); |
|
| 365 | 4 | $oSlideMaster->setTextStyles(new TextStyle(false)); |
|
| 366 | 4 | $oSlideMaster->setRelsIndex('ppt/slideMasters/_rels/' . $baseFile . '.rels'); |
|
| 367 | |||
| 368 | // Background |
||
| 369 | 4 | $oElement = $xmlReader->getElement('/p:sldMaster/p:cSld/p:bg'); |
|
| 370 | 4 | if ($oElement) { |
|
| 371 | 4 | $this->loadSlideBackground($xmlReader, $oElement, $oSlideMaster); |
|
| 372 | } |
||
| 373 | |||
| 374 | // Shapes |
||
| 375 | 4 | $arrayElements = $xmlReader->getElements('/p:sldMaster/p:cSld/p:spTree/*'); |
|
| 376 | 4 | if ($arrayElements) { |
|
| 377 | 4 | $this->loadSlideShapes($oSlideMaster, $arrayElements, $xmlReader); |
|
| 378 | } |
||
| 379 | // Header & Footer |
||
| 380 | |||
| 381 | // ColorMapping |
||
| 382 | 4 | $colorMap = array(); |
|
| 383 | 4 | $oElement = $xmlReader->getElement('/p:sldMaster/p:clrMap'); |
|
| 384 | 4 | if ($oElement->hasAttributes()) { |
|
| 385 | 4 | foreach ($oElement->attributes as $attr) { |
|
| 386 | 4 | $colorMap[$attr->nodeName] = $attr->nodeValue; |
|
| 387 | } |
||
| 388 | 4 | $oSlideMaster->colorMap->setMapping($colorMap); |
|
| 389 | } |
||
| 390 | |||
| 391 | // TextStyles |
||
| 392 | 4 | $arrayElementTxStyles = $xmlReader->getElements('/p:sldMaster/p:txStyles/*'); |
|
| 393 | 4 | if ($arrayElementTxStyles) { |
|
| 394 | 4 | foreach ($arrayElementTxStyles as $oElementTxStyle) { |
|
| 395 | 4 | $arrayElementsLvl = $xmlReader->getElements('/p:sldMaster/p:txStyles/'.$oElementTxStyle->nodeName.'/*'); |
|
| 396 | 4 | foreach ($arrayElementsLvl as $oElementLvl) { |
|
| 397 | 4 | if ($oElementLvl->nodeName == 'a:extLst') { |
|
| 398 | 1 | continue; |
|
| 399 | } |
||
| 400 | 4 | $oRTParagraph = new Paragraph(); |
|
| 401 | |||
| 402 | 4 | if ($oElementLvl->nodeName == 'a:defPPr') { |
|
| 403 | 3 | $level = 0; |
|
| 404 | } else { |
||
| 405 | 4 | $level = str_replace('a:lvl', '', $oElementLvl->nodeName); |
|
| 406 | 4 | $level = str_replace('pPr', '', $level); |
|
| 407 | } |
||
| 408 | |||
| 409 | 4 | if ($oElementLvl->hasAttribute('algn')) { |
|
| 410 | 4 | $oRTParagraph->getAlignment()->setHorizontal($oElementLvl->getAttribute('algn')); |
|
| 411 | } |
||
| 412 | 4 | if ($oElementLvl->hasAttribute('marL')) { |
|
| 413 | 4 | $val = $oElementLvl->getAttribute('marL'); |
|
| 414 | 4 | $val = CommonDrawing::emuToPixels($val); |
|
| 415 | 4 | $oRTParagraph->getAlignment()->setMarginLeft($val); |
|
| 416 | } |
||
| 417 | 4 | if ($oElementLvl->hasAttribute('marR')) { |
|
| 418 | $val = $oElementLvl->getAttribute('marR'); |
||
| 419 | $val = CommonDrawing::emuToPixels($val); |
||
| 420 | $oRTParagraph->getAlignment()->setMarginRight($val); |
||
| 421 | } |
||
| 422 | 4 | if ($oElementLvl->hasAttribute('indent')) { |
|
| 423 | 4 | $val = $oElementLvl->getAttribute('indent'); |
|
| 424 | 4 | $val = CommonDrawing::emuToPixels($val); |
|
| 425 | 4 | $oRTParagraph->getAlignment()->setIndent($val); |
|
| 426 | } |
||
| 427 | 4 | $oElementLvlDefRPR = $xmlReader->getElement('a:defRPr', $oElementLvl); |
|
| 428 | 4 | if ($oElementLvlDefRPR) { |
|
| 429 | 4 | if ($oElementLvlDefRPR->hasAttribute('sz')) { |
|
| 430 | 4 | $oRTParagraph->getFont()->setSize($oElementLvlDefRPR->getAttribute('sz') / 100); |
|
| 431 | } |
||
| 432 | 4 | if ($oElementLvlDefRPR->hasAttribute('b') && $oElementLvlDefRPR->getAttribute('b') == 1) { |
|
| 433 | 1 | $oRTParagraph->getFont()->setBold(true); |
|
| 434 | } |
||
| 435 | 4 | if ($oElementLvlDefRPR->hasAttribute('i') && $oElementLvlDefRPR->getAttribute('i') == 1) { |
|
| 436 | $oRTParagraph->getFont()->setItalic(true); |
||
| 437 | } |
||
| 438 | } |
||
| 439 | 4 | $oElementSchemeColor = $xmlReader->getElement('a:defRPr/a:solidFill/a:schemeClr', $oElementLvl); |
|
| 440 | 4 | if ($oElementSchemeColor) { |
|
| 441 | 4 | if ($oElementSchemeColor->hasAttribute('val')) { |
|
| 442 | 4 | $oRTParagraph->getFont()->setColor(new SchemeColor())->getColor()->setValue($oElementSchemeColor->getAttribute('val')); |
|
| 443 | } |
||
| 444 | } |
||
| 445 | |||
| 446 | 4 | switch ($oElementTxStyle->nodeName) { |
|
| 447 | 4 | case 'p:bodyStyle': |
|
| 448 | 4 | $oSlideMaster->getTextStyles()->setBodyStyleAtLvl($oRTParagraph, $level); |
|
| 449 | 4 | break; |
|
| 450 | 4 | case 'p:otherStyle': |
|
| 451 | 4 | $oSlideMaster->getTextStyles()->setOtherStyleAtLvl($oRTParagraph, $level); |
|
| 452 | 4 | break; |
|
| 453 | 4 | case 'p:titleStyle': |
|
| 454 | 4 | $oSlideMaster->getTextStyles()->setTitleStyleAtLvl($oRTParagraph, $level); |
|
| 455 | 4 | break; |
|
| 456 | } |
||
| 457 | } |
||
| 458 | } |
||
| 459 | } |
||
| 460 | |||
| 461 | // Load the theme |
||
| 462 | 4 | foreach ($this->arrayRels[$oSlideMaster->getRelsIndex()] as $arrayRel) { |
|
| 463 | 4 | if ($arrayRel['Type'] == 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme') { |
|
| 464 | 4 | $pptTheme = $this->oZip->getFromName('ppt/' . substr($arrayRel['Target'], strrpos($arrayRel['Target'], '../') + 3)); |
|
| 465 | 4 | if ($pptTheme !== false) { |
|
| 466 | 4 | $this->loadTheme($pptTheme, $oSlideMaster); |
|
| 467 | } |
||
| 468 | 4 | break; |
|
| 469 | } |
||
| 470 | } |
||
| 471 | |||
| 472 | // Load the Layoutslide |
||
| 473 | 4 | foreach ($xmlReader->getElements('/p:sldMaster/p:sldLayoutIdLst/p:sldLayoutId') as $oElement) { |
|
| 474 | 4 | $rId = $oElement->getAttribute('r:id'); |
|
| 475 | // Get the path to the masterslide from the array with _rels files |
||
| 476 | 4 | $pathLayoutSlide = isset($this->arrayRels[$oSlideMaster->getRelsIndex()][$rId]) ? |
|
| 477 | 4 | $this->arrayRels[$oSlideMaster->getRelsIndex()][$rId]['Target'] : ''; |
|
| 478 | 4 | if (!empty($pathLayoutSlide)) { |
|
| 479 | 4 | $pptLayoutSlide = $this->oZip->getFromName('ppt/' . substr($pathLayoutSlide, strrpos($pathLayoutSlide, '../') + 3)); |
|
| 480 | 4 | if ($pptLayoutSlide !== false) { |
|
| 481 | 4 | $this->loadRels('ppt/slideLayouts/_rels/' . basename($pathLayoutSlide) . '.rels'); |
|
| 482 | 4 | $oSlideMaster->addSlideLayout( |
|
| 483 | 4 | $this->loadLayoutSlide($pptLayoutSlide, basename($pathLayoutSlide), $oSlideMaster) |
|
| 484 | ); |
||
| 485 | } |
||
| 486 | } |
||
| 487 | } |
||
| 488 | } |
||
| 489 | 4 | } |
|
| 490 | |||
| 491 | 4 | private function loadLayoutSlide($sPart, $baseFile, SlideMaster $oSlideMaster) |
|
| 492 | { |
||
| 493 | 4 | $xmlReader = new XMLReader(); |
|
| 494 | 4 | if ($xmlReader->getDomFromString($sPart)) { |
|
| 495 | // Core |
||
| 496 | 4 | $oSlideLayout = new SlideLayout($oSlideMaster); |
|
| 497 | 4 | $oSlideLayout->setRelsIndex('ppt/slideLayouts/_rels/' . $baseFile . '.rels'); |
|
| 498 | |||
| 499 | // Name |
||
| 500 | 4 | $oElement = $xmlReader->getElement('/p:sldLayout/p:cSld'); |
|
| 501 | 4 | if ($oElement && $oElement->hasAttribute('name')) { |
|
| 502 | 4 | $oSlideLayout->setLayoutName($oElement->getAttribute('name')); |
|
| 503 | } |
||
| 504 | |||
| 505 | // Background |
||
| 506 | 4 | $oElement = $xmlReader->getElement('/p:sldLayout/p:cSld/p:bg'); |
|
| 507 | 4 | if ($oElement) { |
|
| 508 | 1 | $this->loadSlideBackground($xmlReader, $oElement, $oSlideLayout); |
|
| 509 | } |
||
| 510 | |||
| 511 | // ColorMapping |
||
| 512 | 4 | $oElement = $xmlReader->getElement('/p:sldLayout/p:clrMapOvr/a:overrideClrMapping'); |
|
| 513 | 4 | if ($oElement && $oElement->hasAttributes()) { |
|
| 514 | 1 | $colorMap = array(); |
|
| 515 | 1 | foreach ($oElement->attributes as $attr) { |
|
| 516 | 1 | $colorMap[$attr->nodeName] = $attr->nodeValue; |
|
| 517 | } |
||
| 518 | 1 | $oSlideLayout->colorMap->setMapping($colorMap); |
|
| 519 | } |
||
| 520 | |||
| 521 | // Shapes |
||
| 522 | 4 | $oElements = $xmlReader->getElements('/p:sldLayout/p:cSld/p:spTree/*'); |
|
| 523 | 4 | if ($oElements) { |
|
| 524 | 4 | $this->loadSlideShapes($oSlideLayout, $oElements, $xmlReader); |
|
| 525 | } |
||
| 526 | 4 | $this->arraySlideLayouts[$baseFile] = &$oSlideLayout; |
|
| 527 | 4 | return $oSlideLayout; |
|
| 528 | } |
||
| 529 | return null; |
||
| 530 | } |
||
| 531 | |||
| 532 | /** |
||
| 533 | * @param string $sPart |
||
| 534 | * @param SlideMaster $oSlideMaster |
||
| 535 | */ |
||
| 536 | 4 | private function loadTheme($sPart, SlideMaster $oSlideMaster) |
|
| 558 | |||
| 559 | /** |
||
| 560 | * @param XMLReader $xmlReader |
||
| 561 | * @param \DOMElement $oElement |
||
| 562 | * @param AbstractSlide $oSlide |
||
| 563 | */ |
||
| 564 | 4 | private function loadSlideBackground(XMLReader $xmlReader, \DOMElement $oElement, AbstractSlide $oSlide) |
|
| 619 | |||
| 620 | /** |
||
| 621 | * |
||
| 622 | * @param XMLReader $document |
||
| 623 | * @param \DOMElement $node |
||
| 624 | * @param AbstractSlide $oSlide |
||
| 625 | */ |
||
| 626 | 3 | protected function loadShapeDrawing(XMLReader $document, \DOMElement $node, AbstractSlide $oSlide) |
|
| 725 | |||
| 726 | /** |
||
| 727 | * @param XMLReader $document |
||
| 728 | * @param \DOMElement $node |
||
| 729 | * @param AbstractSlide $oSlide |
||
| 730 | * @throws \Exception |
||
| 731 | */ |
||
| 732 | 4 | protected function loadShapeRichText(XMLReader $document, \DOMElement $node, AbstractSlide $oSlide) |
|
| 881 | |||
| 882 | /** |
||
| 883 | * |
||
| 884 | * @param string $fileRels |
||
| 885 | * @return string |
||
| 886 | */ |
||
| 887 | 4 | protected function loadRels($fileRels) |
|
| 902 | |||
| 903 | /** |
||
| 904 | * @param $oSlide |
||
| 905 | * @param $oElements |
||
| 906 | * @param $xmlReader |
||
| 907 | * @internal param $baseFile |
||
| 908 | */ |
||
| 909 | 4 | private function loadSlideShapes($oSlide, $oElements, $xmlReader) |
|
| 924 | } |
||
| 925 |
This check marks calls to methods that do not seem to exist on an object.
This is most likely the result of a method being renamed without all references to it being renamed likewise.