From d2f66802f6fb4b86545bf96e8c3c2de5d26cdaf9 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Wed, 13 Dec 2023 15:30:29 +0100 Subject: [PATCH] Feedbacks from @Progi1984 --- .gitignore | 1 + docs/changes/1.1.0.md | 13 + docs/usage/presentation.md | 32 +- docs/usage/styles.md | 35 +- samples/Sample_04_Table.php | 2 +- samples/Sample_05_Chart.php | 4 +- samples/Sample_17_Comment.php | 6 +- samples/Sample_22_ExternalSlide.php | 2 +- samples/Sample_Header.php | 13 +- src/PhpPresentation/AbstractShape.php | 104 ++---- src/PhpPresentation/DocumentProperties.php | 61 ++-- .../Exception/InvalidParameterException.php | 11 +- .../PresentationProperties.php | 69 ++-- src/PhpPresentation/Reader/ODPresentation.php | 5 +- src/PhpPresentation/Reader/PowerPoint2007.php | 238 ++++++-------- src/PhpPresentation/Reader/PowerPoint97.php | 2 +- src/PhpPresentation/Reader/Serialized.php | 13 +- src/PhpPresentation/Shape/AbstractGraphic.php | 31 -- src/PhpPresentation/Shape/Chart/Legend.php | 22 +- src/PhpPresentation/Shape/Chart/Title.php | 12 +- .../Shape/Chart/Type/AbstractTypeBar.php | 4 +- src/PhpPresentation/Shape/Chart/View3D.php | 8 +- src/PhpPresentation/Shape/Drawing/Gd.php | 4 +- src/PhpPresentation/Shape/Group.php | 32 +- src/PhpPresentation/Shape/RichText.php | 94 ++---- .../Shape/RichText/Paragraph.php | 71 +--- src/PhpPresentation/Shape/RichText/Run.php | 61 +--- .../Shape/RichText/TextElement.php | 4 +- .../Shape/RichText/TextElementInterface.php | 4 +- src/PhpPresentation/Shape/Table/Cell.php | 14 +- .../ShapeContainerInterface.php | 9 +- src/PhpPresentation/Slide.php | 34 +- src/PhpPresentation/Slide/AbstractSlide.php | 62 +--- src/PhpPresentation/Slide/Animation.php | 37 +-- src/PhpPresentation/Slide/Iterator.php | 11 +- src/PhpPresentation/Slide/Note.php | 35 +- src/PhpPresentation/Slide/SlideLayout.php | 5 +- src/PhpPresentation/Slide/SlideMaster.php | 3 - src/PhpPresentation/Style/Borders.php | 24 +- src/PhpPresentation/Style/Bullet.php | 10 +- src/PhpPresentation/Style/Color.php | 4 +- src/PhpPresentation/Style/Effect.php | 310 ------------------ src/PhpPresentation/Style/Font.php | 251 +++++++------- src/PhpPresentation/Style/Shadow.php | 37 ++- .../Traits/ShapeCollection.php | 96 ++++++ .../Writer/AbstractDecoratorWriter.php | 2 +- src/PhpPresentation/Writer/AbstractWriter.php | 16 +- src/PhpPresentation/Writer/ODPresentation.php | 2 +- .../Writer/ODPresentation/Content.php | 11 +- .../Writer/ODPresentation/ObjectsChart.php | 4 +- src/PhpPresentation/Writer/PowerPoint2007.php | 2 +- .../Writer/PowerPoint2007/AbstractSlide.php | 148 +++------ .../Writer/PowerPoint2007/ContentTypes.php | 2 +- .../Writer/PowerPoint2007/DocPropsCore.php | 11 +- .../PowerPoint2007/DocPropsThumbnail.php | 23 +- .../Writer/PowerPoint2007/PptCharts.php | 64 ++-- .../Writer/PowerPoint2007/PptSlides.php | 83 ++--- .../Writer/PowerPoint2007/Relationships.php | 23 +- src/PhpPresentation/Writer/Serialized.php | 22 +- .../Tests/DocumentPropertiesTest.php | 2 + .../Tests/PresentationPropertiesTest.php | 26 +- .../Tests/Reader/PowerPoint2007Test.php | 2 + .../PhpPresentation/Tests/Shape/GroupTest.php | 4 +- .../Tests/Shape/RichTextTest.php | 2 +- .../Tests/Slide/AbstractSlideTest.php | 34 ++ .../PhpPresentation/Tests/Slide/NoteTest.php | 8 +- .../Tests/Slide/SlideLayoutTest.php | 2 +- .../Tests/Slide/SlideMasterTest.php | 2 +- .../Tests/Style/BorderTest.php | 6 +- .../PhpPresentation/Tests/Style/ColorTest.php | 2 +- .../PhpPresentation/Tests/Style/FillTest.php | 8 +- .../PhpPresentation/Tests/Style/FontTest.php | 86 ++++- .../PowerPoint2007/DocPropsCoreTest.php | 18 +- .../PowerPoint2007/DocPropsThumbnailTest.php | 30 +- .../PowerPoint2007/PptSlideMastersTest.php | 2 +- .../Writer/PowerPoint2007/PptSlidesTest.php | 141 ++++++++ .../_includes/PhpPresentationTestCase.php | 12 + tests/bootstrap.php | 2 +- tests/resources/files/serialized.phppt | Bin 14433 -> 14495 bytes 79 files changed, 1192 insertions(+), 1510 deletions(-) delete mode 100644 src/PhpPresentation/Style/Effect.php create mode 100644 src/PhpPresentation/Traits/ShapeCollection.php diff --git a/.gitignore b/.gitignore index afe22ddd1..4cdc9c601 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ Desktop.ini ### Continuous Integration build/ phpunit.xml +php-cs-fixer.phar .php-cs-fixer.cache .phpunit.result.cache composer.phar diff --git a/docs/changes/1.1.0.md b/docs/changes/1.1.0.md index 81ba6ae1e..103d901a0 100644 --- a/docs/changes/1.1.0.md +++ b/docs/changes/1.1.0.md @@ -17,9 +17,22 @@ - PowerPoint2007 Reader - PowerPoint2007 Writer - PowerPoint2007 Writer: Enable style and position of a Placeholder - [@qmachard](https://github.com/qmachard) in [#787](https://github.com/PHPOffice/PHPPresentation/pull/787) +- PowerPoint2007 Reader: Added support for thumbnail - [@devX2712](https://github.com/devX2712) in [#788](https://github.com/PHPOffice/PHPPresentation/pull/787) ## Improvements - Slide : Raised max value for identifier rand call - [@Scheissy](https://github.com/Scheissy) in [#777](https://github.com/PHPOffice/PHPPresentation/pull/777) +- Document Properties : Support for Revision & Status - [@devX2712](https://github.com/devX2712) in [#788](https://github.com/PHPOffice/PHPPresentation/pull/787) + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Presentation Properties : Added support to define content of the thumbnail - [@devX2712](https://github.com/devX2712) in [#788](https://github.com/PHPOffice/PHPPresentation/pull/787) +- Font : Support for Strikethrough mode - [@devX2712](https://github.com/devX2712) in [#788](https://github.com/PHPOffice/PHPPresentation/pull/787) + - PowerPoint2007 Reader + - PowerPoint2007 Writer +- Font : Support for Pitch Family, Charset & Panose - [@devX2712](https://github.com/devX2712) in [#788](https://github.com/PHPOffice/PHPPresentation/pull/787) + - PowerPoint2007 Reader + - PowerPoint2007 Writer +(@todo Doc) +- Font : Replaced Superscript/Subscript by baseline in PowerPoint2007 Writer - [@devX2712](https://github.com/devX2712) in [#788](https://github.com/PHPOffice/PHPPresentation/pull/787) ## Bugfixes diff --git a/docs/usage/presentation.md b/docs/usage/presentation.md index 03080aa1c..a06e0958b 100644 --- a/docs/usage/presentation.md +++ b/docs/usage/presentation.md @@ -62,6 +62,8 @@ $properties->setCreated(mktime(0, 0, 0, 3, 12, 2014)); $properties->setModified(mktime(0, 0, 0, 3, 14, 2014)); $properties->setSubject('My subject'); $properties->setKeywords('my, key, word'); +$properties->setStatus('Work in Progress'); +$properties->setRevision('Version 1.2.3'); ``` ### Custom Properties @@ -203,16 +205,44 @@ echo $properties->getSlideshowType(); You can define the thumbnail of the presentation with the method `setThumbnailPath`. + +#### From a file ``` php getPresentationProperties(); // Set path of the thumbnail -$properties->setThumbnailPath(__DIR__.'\resources\phppowerpoint_logo.gif'); +$properties->setThumbnailPath( + __DIR__.'\resources\phppowerpoint_logo.gif', + PresentationProperties::THUMBNAIL_FILE +); // Get path of the thumbnail echo $properties->getThumbnailPath(); +// Get content of the thumbnail +echo $properties->getThumbnail(); +``` + +#### From the content of the file +``` php +getPresentationProperties(); +// Set path of the thumbnail +$properties->setThumbnailPath( + '', + PresentationProperties::THUMBNAIL_DATA, + file_get_contents(__DIR__.'\resources\phppowerpoint_logo.gif') +); +// Get content of the thumbnail +echo $properties->getThumbnail(); ``` ### Zoom diff --git a/docs/usage/styles.md b/docs/usage/styles.md index e9ff72c60..a21efdc8e 100644 --- a/docs/usage/styles.md +++ b/docs/usage/styles.md @@ -97,12 +97,24 @@ echo $alignment->isRTL(); - `name` - `bold` - `italic` -- `superScript` -- `subScript` +- `superScript` (deprecated) +- `subScript` (deprecated) - `underline` - `strikethrough` - `color` -- `capitalization` +- `pitchFamily` +- `charset` + +### Baseline + +The baseline set the position relative to the line. +The value is a percentage. + +You can use some predefined values : + +* `Font::BASELINE_SUPERSCRIPT` (= 300000 = 300%) +* `Font::BASELINE_SUBSCRIPT` (= -250000 = -250%) + ### Capitalization @@ -145,6 +157,23 @@ $font->setFormat(Font::FORMAT_EAST_ASIAN); // Get format of font echo $font->getFormat(); ``` + +### Panose +The support of Panose 1.0 is only used. + +``` php +setPanose('4494D72242'); +// Get panose of font +echo $font->getPanose(); +``` + ## Bullet - `bulletType` diff --git a/samples/Sample_04_Table.php b/samples/Sample_04_Table.php index 0dce634c6..e6558d623 100644 --- a/samples/Sample_04_Table.php +++ b/samples/Sample_04_Table.php @@ -85,7 +85,7 @@ $oCell->createTextRun('R2C1'); $oCell->getActiveParagraph()->getAlignment() ->setMarginLeft(30) - ->setTextDirection(\PhpOffice\PhpPresentation\Style\Alignment::TEXT_DIRECTION_VERTICAL_270); + ->setTextDirection(PhpOffice\PhpPresentation\Style\Alignment::TEXT_DIRECTION_VERTICAL_270); $oCell = $row->nextCell(); $oCell->createTextRun('R2C2'); $oCell->getActiveParagraph()->getAlignment() diff --git a/samples/Sample_05_Chart.php b/samples/Sample_05_Chart.php index 201d9a46a..ad9c32f74 100644 --- a/samples/Sample_05_Chart.php +++ b/samples/Sample_05_Chart.php @@ -132,7 +132,7 @@ function fnSlide_BarHorizontal(PhpPresentation $objPHPPresentation): void // Create a bar chart (that should be inserted in a shape) echo date('H:i:s') . ' Create a horizontal bar chart (that should be inserted in a chart shape) ' . EOL; - $barChartHorz = clone $objPHPPresentation->getSlide(1)->getShapeCollection()->offsetGet(1)->getPlotArea()->getType(); + $barChartHorz = clone $objPHPPresentation->getSlide(1)->getShapeCollection()[1]->getPlotArea()->getType(); $barChartHorz->setBarDirection(Bar3D::DIRECTION_HORIZONTAL); // Create templated slide @@ -363,7 +363,7 @@ function fnSlide_Bar3DHorizontal(PhpPresentation $objPHPPresentation): void // Create a bar chart (that should be inserted in a shape) echo date('H:i:s') . ' Create a horizontal bar chart (that should be inserted in a chart shape) ' . EOL; - $bar3DChartHorz = clone $objPHPPresentation->getSlide(5)->getShapeCollection()->offsetGet(1)->getPlotArea()->getType(); + $bar3DChartHorz = clone $objPHPPresentation->getSlide(5)->getShapeCollection()[1]->getPlotArea()->getType(); $bar3DChartHorz->setBarDirection(Bar3D::DIRECTION_HORIZONTAL); // Create templated slide diff --git a/samples/Sample_17_Comment.php b/samples/Sample_17_Comment.php index c9fa84926..d417c4bfd 100644 --- a/samples/Sample_17_Comment.php +++ b/samples/Sample_17_Comment.php @@ -14,13 +14,13 @@ $oSlide1->addShape(clone $oShapeDrawing); $oSlide1->addShape(clone $oShapeRichText); -$oAuthor = new \PhpOffice\PhpPresentation\Shape\Comment\Author(); +$oAuthor = new PhpOffice\PhpPresentation\Shape\Comment\Author(); $oAuthor->setName('Progi1984'); $oAuthor->setInitials('P'); // Add Comment 1 echo date('H:i:s') . ' Add Comment 1' . EOL; -$oComment1 = new \PhpOffice\PhpPresentation\Shape\Comment(); +$oComment1 = new PhpOffice\PhpPresentation\Shape\Comment(); $oComment1->setText('Text A'); $oComment1->setOffsetX(10); $oComment1->setOffsetY(55); @@ -30,7 +30,7 @@ // Add Comment echo date('H:i:s') . ' Add Comment 2' . EOL; -$oComment2 = new \PhpOffice\PhpPresentation\Shape\Comment(); +$oComment2 = new PhpOffice\PhpPresentation\Shape\Comment(); $oComment2->setText('Text B'); $oComment2->setOffsetX(170); $oComment2->setOffsetY(180); diff --git a/samples/Sample_22_ExternalSlide.php b/samples/Sample_22_ExternalSlide.php index 3e89bf3d2..763234a6b 100644 --- a/samples/Sample_22_ExternalSlide.php +++ b/samples/Sample_22_ExternalSlide.php @@ -9,7 +9,7 @@ $objPHPPresentation = new PhpPresentation(); $objPHPPresentation->removeSlideByIndex(0); -$oReader = \PhpOffice\PhpPresentation\IOFactory::createReader('PowerPoint2007'); +$oReader = PhpOffice\PhpPresentation\IOFactory::createReader('PowerPoint2007'); $oPresentation04 = $oReader->load(__DIR__ . '/results/Sample_04_Table.pptx'); foreach ($oPresentation04->getAllSlides() as $oSlide) { diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 61796fe6f..803480e29 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -31,7 +31,7 @@ } else { if (is_file(__DIR__ . '/../../Common/src/Common/Autoloader.php')) { include_once __DIR__ . '/../../Common/src/Common/Autoloader.php'; - \PhpOffice\Common\Autoloader::register(); + PhpOffice\Common\Autoloader::register(); } else { throw new Exception('Can not find the vendor or the common folder!'); } @@ -109,7 +109,7 @@ /** * Write documents. * - * @param \PhpOffice\PhpPresentation\PhpPresentation $phpPresentation + * @param PhpPresentation $phpPresentation * @param string $filename * @param array $writers * @@ -180,7 +180,7 @@ function getEndingNotes($writers) /** * Creates a templated slide. */ -function createTemplatedSlide(PHPPresentation $objPHPPresentation): Slide +function createTemplatedSlide(PhpPresentation $objPHPPresentation): Slide { // Create slide $slide = $objPHPPresentation->createSlide(); @@ -326,7 +326,7 @@ protected function displayPhpPresentationInfo(PhpPresentation $oPHPPpt): void } } $oNote = $oSlide->getNote(); - if ($oNote->getShapeCollection()->count() > 0) { + if (count($oNote->getShapeCollection()) > 0) { $this->append('
Notes
'); foreach ($oNote->getShapeCollection() as $oShape) { if ($oShape instanceof RichText) { @@ -366,11 +366,11 @@ protected function displayShapeInfo(AbstractShape $oShape): void $this->append('
None
'); } else { switch ($oShape->getFill()->getFillType()) { - case \PhpOffice\PhpPresentation\Style\Fill::FILL_NONE: + case PhpOffice\PhpPresentation\Style\Fill::FILL_NONE: $this->append('
None
'); break; - case \PhpOffice\PhpPresentation\Style\Fill::FILL_SOLID: + case PhpOffice\PhpPresentation\Style\Fill::FILL_SOLID: $this->append('
Solid ('); $this->append('Color : #' . $oShape->getFill()->getStartColor()->getRGB()); $this->append(' - Alpha : ' . $oShape->getFill()->getStartColor()->getAlpha() . '%'); @@ -442,6 +442,7 @@ protected function displayShapeInfo(AbstractShape $oShape): void $this->append('Italic : ' . ($oRichText->getFont()->isItalic() ? 'Y' : 'N') . ' - '); $this->append('Underline : Underline::' . $this->getConstantName('\PhpOffice\PhpPresentation\Style\Font', $oRichText->getFont()->getUnderline()) . ' - '); $this->append('Strikethrough : ' . ($oRichText->getFont()->isStrikethrough() ? 'Y' : 'N') . ' - '); + $this->append('Baseline : ' . $oRichText->getFont()->getBaseline() . ' - '); $this->append('SubScript : ' . ($oRichText->getFont()->isSubScript() ? 'Y' : 'N') . ' - '); $this->append('SuperScript : ' . ($oRichText->getFont()->isSuperScript() ? 'Y' : 'N')); $this->append('
'); diff --git a/src/PhpPresentation/AbstractShape.php b/src/PhpPresentation/AbstractShape.php index 176247149..bbe9de54d 100644 --- a/src/PhpPresentation/AbstractShape.php +++ b/src/PhpPresentation/AbstractShape.php @@ -20,6 +20,7 @@ namespace PhpOffice\PhpPresentation; use PhpOffice\PhpPresentation\Exception\ShapeContainerAlreadyAssignedException; +use PhpOffice\PhpPresentation\Shape\Group; use PhpOffice\PhpPresentation\Shape\Hyperlink; use PhpOffice\PhpPresentation\Shape\Placeholder; use PhpOffice\PhpPresentation\Style\Border; @@ -103,27 +104,21 @@ abstract class AbstractShape implements ComparableInterface protected $placeholder; /** - * List of effect apply to shape - * @var array \PhpOffice\PhpPresentation\Style\Effect[] - */ - protected ?array $effectCollection = null; - - /** - * Hash index + * Hash index. * * @var int */ private $hashIndex; /** - * Name + * Name. * * @var string */ protected $name = ''; - + /** - * Create a new self + * Create a new self. */ public function __construct() { @@ -131,9 +126,8 @@ public function __construct() $this->fill = new Fill(); $this->shadow = new Shadow(); $this->border = new Border(); - $this->effectCollection = null; - $this->border->setLineStyle(Style\Border::LINE_NONE); + $this->border->setLineStyle(Border::LINE_NONE); } /** @@ -143,26 +137,19 @@ public function __clone() { $this->container = null; $this->name = $this->name; + $this->border = clone $this->border; if (isset($this->fill)) { - $this->fill = clone $this->fill; - } - if (isset($this->border)) { - $this->border = clone $this->border; + $this->fill = clone $this->fill; } if (isset($this->shadow)) { - $this->shadow = clone $this->shadow; + $this->shadow = clone $this->shadow; } if (isset($this->placeholder)) { - $this->placeholder = clone $this->placeholder; + $this->placeholder = clone $this->placeholder; } if (isset($this->hyperlink)) { - $this->hyperlink = clone $this->hyperlink; + $this->hyperlink = clone $this->hyperlink; } - // Clone each effect - if (isset($this->effectCollection)) { - foreach ($this->effectCollection as &$effect) { - $effect = clone $effect; - }} } /** @@ -186,21 +173,18 @@ public function setContainer(?ShapeContainerInterface $pValue = null, $pOverride // Add drawing to ShapeContainerInterface $this->container = $pValue; if (null !== $this->container) { - $this->container->getShapeCollection()->append($this); + $this->container->addShape($this); } } else { if ($pOverrideOld) { // Remove drawing from old ShapeContainerInterface - $iterator = $this->container->getShapeCollection()->getIterator(); - - while ($iterator->valid()) { - if ($iterator->current()->getHashCode() == $this->getHashCode()) { - $this->container->getShapeCollection()->offsetUnset($iterator->key()); + foreach ($this->container->getShapeCollection() as $key => $shape) { + if ($shape->getHashCode() == $this->getHashCode()) { + $this->container->unsetShape($key); $this->container = null; break; } - $iterator->next(); } // Set new \PhpOffice\PhpPresentation\Slide @@ -214,31 +198,27 @@ public function setContainer(?ShapeContainerInterface $pValue = null, $pOverride } /** - * Get Name - * - * @return string + * Get Name. */ - public function getName() + public function getName(): string { return $this->name; } /** - * Set Name + * Set Name. * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Shape\AbstractGraphic + * @return static */ - public function setName($pValue = '') + public function setName(string $pValue = ''): self { $this->name = $pValue; + return $this; } /** - * Get OffsetX - * - * @return int + * Get OffsetX. */ public function getOffsetX(): int { @@ -423,46 +403,6 @@ public function setHyperlink(?Hyperlink $pHyperlink = null): self return $this; } - - /** - * Add an effect to the shpae - * - * @param \PhpOffice\PhpPresentation\Style\Effect $effect - * @return $this - */ - public function addEffect(Shape\Effect $effect) - { - if (!isset($this->effectCollection)) { - $this->effectCollection = array(); - } - $this->effectCollection[] = $effect; - return $this; - } - - /** - * Get the effect collection - * - * @return array \PhpOffice\PhpPresentation\Style\Effect[] - */ - public function getEffectCollection():?array - { - return $this->effectCollection; - } - - /** - * Set the effect collection - * - * @param array \PhpOffice\PhpPresentation\Style\Effect $effectCollection - * @return $this - */ - public function setEffectCollection(array $effectCollection) - { - if ( isset($effectCollection) - && is_array($effectCollection)) { - $this->effectCollection = $effectCollection; - } - return $this; - } /** * Get hash code. diff --git a/src/PhpPresentation/DocumentProperties.php b/src/PhpPresentation/DocumentProperties.php index c6a24e453..041d2fc27 100644 --- a/src/PhpPresentation/DocumentProperties.php +++ b/src/PhpPresentation/DocumentProperties.php @@ -100,30 +100,30 @@ class DocumentProperties * @var string */ private $company; - + /** - * revision + * Revision. * * @var string */ private $revision; - + /** - * Custom Properties. + * Status. * - * @var array> + * @var string */ - private $customProperties = []; + private $status; /** - * status + * Custom Properties. * - * @var string + * @var array> */ - private $status; + private $customProperties = []; /** - * Create a new \PhpOffice\PhpPresentation\DocumentProperties + * Create a new \PhpOffice\PhpPresentation\DocumentProperties. */ public function __construct() { @@ -139,7 +139,7 @@ public function __construct() $this->category = ''; $this->company = 'Microsoft Corporation'; $this->revision = ''; - $this->status = ''; + $this->status = ''; } /** @@ -157,7 +157,7 @@ public function getCreator() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setCreator($pValue = '') { @@ -181,7 +181,7 @@ public function getLastModifiedBy() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setLastModifiedBy($pValue = '') { @@ -205,7 +205,7 @@ public function getCreated() * * @param int $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setCreated($pValue = null) { @@ -232,7 +232,7 @@ public function getModified() * * @param int $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setModified($pValue = null) { @@ -259,7 +259,7 @@ public function getTitle() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setTitle($pValue = '') { @@ -283,7 +283,7 @@ public function getDescription() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setDescription($pValue = '') { @@ -307,7 +307,7 @@ public function getSubject() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setSubject($pValue = '') { @@ -331,7 +331,7 @@ public function getKeywords() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setKeywords($pValue = '') { @@ -355,7 +355,7 @@ public function getCategory() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setCategory($pValue = '') { @@ -379,7 +379,7 @@ public function getCompany() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\DocumentProperties + * @return DocumentProperties */ public function setCompany($pValue = '') { @@ -470,16 +470,14 @@ public function setCustomProperty(string $propertyName, $propertyValue = '', ?st return $this; } - /* - * Get Revision. - */ + // Get Revision. public function getRevision(): string { return $this->revision; } /** - * Set Revision + * Set Revision. */ public function setRevision(string $pValue = ''): self { @@ -489,22 +487,17 @@ public function setRevision(string $pValue = ''): self } /** - * Get Status - * - * @return string + * Get Status. */ - public function getStatus() + public function getStatus(): string { return $this->status; } /** - * Set Status - * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\DocumentProperties + * Set Status. */ - public function setStatus($pValue = '') + public function setStatus(string $pValue = ''): self { $this->status = $pValue; diff --git a/src/PhpPresentation/Exception/InvalidParameterException.php b/src/PhpPresentation/Exception/InvalidParameterException.php index 961809623..5a426ea61 100644 --- a/src/PhpPresentation/Exception/InvalidParameterException.php +++ b/src/PhpPresentation/Exception/InvalidParameterException.php @@ -21,12 +21,17 @@ class InvalidParameterException extends PhpPresentationException { - public function __construct(string $parameter, string $value) + public function __construct(string $parameter, string $value, ?string $error = null) { - parent::__construct(sprintf( + $message = sprintf( 'The parameter %s can\'t have the value "%s"', $parameter, $value - )); + ); + if ($error) { + $message = sprintf('%s (Validation: %s)', $message, $error); + } + + parent::__construct($message); } } diff --git a/src/PhpPresentation/PresentationProperties.php b/src/PhpPresentation/PresentationProperties.php index 63eca8fb5..dce8f439d 100644 --- a/src/PhpPresentation/PresentationProperties.php +++ b/src/PhpPresentation/PresentationProperties.php @@ -30,8 +30,8 @@ class PresentationProperties public const VIEW_SLIDE_SORTER = 'sldSorterView'; public const VIEW_SLIDE_THUMBNAIL = 'sldThumbnailView'; - public const THUMBNAIL_FILE = 'file'; // Thumbnail path is out of PPT - public const THUMBNAIL_ZIP = 'zip'; // Thumbnail path point to an image store into file loaded + public const THUMBNAIL_FILE = 'file'; + public const THUMBNAIL_DATA = 'data'; /** * @var array @@ -72,17 +72,17 @@ class PresentationProperties */ protected $markAsFinal = false; - /* - * @var string Define the thumbnail content (if content into zip file) + /** + * @var null|string Define the thumbnail content (if content into zip file) */ - protected $thumbnail = null; + protected $thumbnail; - /* - * @var string Define the thumbnail place + /** + * @var null|string Define the thumbnail place */ - protected $thumbnailPath = ''; + protected $thumbnailPath; - /* + /** * @var string Define if thumbnail is out of PPT or previouly store into PPT */ protected $thumbnailType = self::THUMBNAIL_FILE; @@ -128,38 +128,40 @@ public function getThumbnailPath(): ?string { return $this->thumbnailPath; } - + /** - * Return the content of thumbnail - * - * @return binary Content of image + * Return the content of thumbnail. */ - public function getThumbnail() + public function getThumbnail(): ?string { - // Return content of local file - if ($this->getThumbnailType() == self::THUMBNAIL_FILE) { - if (file_exists($this->getThumbnailPath())) - return file_get_contents($this->getThumbnailPath()); - } - // Return content of image stored into zip file - if ($this->getThumbnailType() == self::THUMBNAIL_ZIP) { - return $this->thumbnail; - } - // Return null if no thumbnail - return null; + // Return content of local file + if ($this->getThumbnailType() == self::THUMBNAIL_FILE) { + if ($this->getThumbnailPath()) { + return file_get_contents($this->getThumbnailPath()); + } + + return null; + } + + // Return content of image stored into zip file + if ($this->getThumbnailType() == self::THUMBNAIL_DATA) { + return $this->thumbnail; + } + + return null; } /** * Define the path for the thumbnail file / preview picture. */ - public function setThumbnailPath(string $path = '', $type = self::THUMBNAIL_FILE, $content = null) + public function setThumbnailPath(string $path = '', string $type = self::THUMBNAIL_FILE, ?string $content = null): self { - if (file_exists($path) && ($type == self::THUMBNAIL_FILE)) { + if (file_exists($path) && $type == self::THUMBNAIL_FILE) { $this->thumbnailPath = $path; $this->thumbnailType = $type; } - if (($path != '') && ($type == self::THUMBNAIL_ZIP)) { - $this->thumbnailPath = $path; + if ($content != '' && $type == self::THUMBNAIL_DATA) { + $this->thumbnailPath = ''; $this->thumbnailType = $type; $this->thumbnail = $content; } @@ -168,16 +170,15 @@ public function setThumbnailPath(string $path = '', $type = self::THUMBNAIL_FILE } /** - * Return the thumbnail type - * @return string + * Return the thumbnail type. */ - public function getThumbnailType() + public function getThumbnailType(): string { return $this->thumbnailType; } - + /** - * Mark a document as final + * Mark a document as final. */ public function markAsFinal(bool $state = true): self { diff --git a/src/PhpPresentation/Reader/ODPresentation.php b/src/PhpPresentation/Reader/ODPresentation.php index 0261b3689..579fab676 100644 --- a/src/PhpPresentation/Reader/ODPresentation.php +++ b/src/PhpPresentation/Reader/ODPresentation.php @@ -32,6 +32,7 @@ use PhpOffice\PhpPresentation\Shape\Drawing\Gd; use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; +use PhpOffice\PhpPresentation\Slide\Background\Color as BackgroundColor; use PhpOffice\PhpPresentation\Slide\Background\Image; use PhpOffice\PhpPresentation\Style\Alignment; use PhpOffice\PhpPresentation\Style\Bullet; @@ -71,7 +72,7 @@ class ODPresentation implements ReaderInterface protected $arrayCommonStyles = []; /** - * @var \PhpOffice\Common\XMLReader + * @var XMLReader */ protected $oXMLReader; @@ -258,7 +259,7 @@ protected function loadStyle(DOMElement $nodeStyle): bool if ($nodeDrawingPageProps instanceof DOMElement) { // Read Background Color if ($nodeDrawingPageProps->hasAttribute('draw:fill-color') && 'solid' == $nodeDrawingPageProps->getAttribute('draw:fill')) { - $oBackground = new \PhpOffice\PhpPresentation\Slide\Background\Color(); + $oBackground = new BackgroundColor(); $oColor = new Color(); $oColor->setRGB(substr($nodeDrawingPageProps->getAttribute('draw:fill-color'), -6)); $oBackground->setColor($oColor); diff --git a/src/PhpPresentation/Reader/PowerPoint2007.php b/src/PhpPresentation/Reader/PowerPoint2007.php index e619a2607..140c2f4a5 100644 --- a/src/PhpPresentation/Reader/PowerPoint2007.php +++ b/src/PhpPresentation/Reader/PowerPoint2007.php @@ -51,6 +51,7 @@ use PhpOffice\PhpPresentation\Style\Fill; use PhpOffice\PhpPresentation\Style\Font; use PhpOffice\PhpPresentation\Style\SchemeColor; +use PhpOffice\PhpPresentation\Style\Shadow; use PhpOffice\PhpPresentation\Style\TextStyle; use ZipArchive; @@ -230,7 +231,7 @@ protected function loadDocumentProperties(string $sPart): void '/cp:coreProperties/dcterms:modified' => 'setModified', '/cp:coreProperties/cp:revision' => 'setRevision', '/cp:coreProperties/cp:contentStatus' => 'setStatus', - ); + ]; $oProperties = $this->oPhpPresentation->getDocumentProperties(); foreach ($arrayProperties as $path => $property) { $oElement = $xmlReader->getElement($path); @@ -247,28 +248,24 @@ protected function loadDocumentProperties(string $sPart): void } /** - * Read information of the document thumbnail - * @param string $sPart Content of XML file for retrieving data + * Read information of the document thumbnail. */ - protected function loadThumbnailProperties($sPart) + protected function loadThumbnailProperties(string $sPart): void { $xmlReader = new XMLReader(); - if ($xmlReader->getDomFromString($sPart)) { - $oElement = $xmlReader->getElement('*[@Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"]'); - if ($oElement instanceof \DOMElement) { + $xmlReader->getDomFromString($sPart); + + $oElement = $xmlReader->getElement('*[@Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"]'); + if ($oElement instanceof DOMElement) { $path = $oElement->getAttribute('Target'); $this->oPhpPresentation - ->getPresentationProperties() - ->setThumbnailPath($path - , \PhpOffice\PhpPresentation\PresentationProperties::THUMBNAIL_ZIP - , $this->oZip->getFromName($path)); - } + ->getPresentationProperties() + ->setThumbnailPath('', PresentationProperties::THUMBNAIL_DATA, $this->oZip->getFromName($path)); } } /** - * Read Custom Properties - * @param string $sPart + * Read Custom Properties. */ protected function loadCustomProperties(string $sPart): void { @@ -878,79 +875,62 @@ protected function loadShapeDrawing(XMLReader $document, DOMElement $node, Abstr } } // Load shape effects - $oEffect = $document->getElement('p:spPr/a:effectLst', $node); - if ($oEffect instanceof \DOMElement) { - $aEffect = $this->loadEffect($document, $oEffect); - if (isset($aEffect) && is_array($aEffect)) { - $oShape->setEffectCollection($aEffect); - } + $oElement = $document->getElement('p:spPr/a:effectLst', $node); + if ($oElement instanceof DOMElement) { + $oShape->setShadow( + $this->loadShadow($document, $oElement) + ); } $oSlide->addShape($oShape); } - + /** - * Load Effect for shape or paragraph - * - * @param XMLReader $document - * @param \DOMElement $node - * @return array \PhpOffice\PhpPresentation\Style\Effect[] + * Load Shadow for shape or paragraph. */ - protected function loadEffect(XMLReader $document, \DOMElement $nodeEffect) + protected function loadShadow(XMLReader $document, DOMElement $node): ?Shadow { - $aEffect = null; - if ($nodeEffect instanceof \DOMElement) { - - $aNodes = $document->getElements('*', $nodeEffect); - foreach ($aNodes as $node) { - - $type = explode(':', $node->tagName); - $type = array_pop($type); - if ( $type == 'outerShdw' - || $type == 'innerShdw') { -// @TODO || $type == 'reflection') { - - // Create a new effect - $effect = new \PhpOffice\PhpPresentation\Style\Effect($type); - // load blur radius - if ($node->hasAttribute('blurRad')) { - $effect->setBlurRadius(CommonDrawing::emuToPixels($node->getAttribute('blurRad'))); - } - // load distance - if ($node->hasAttribute('dist')) { - $effect->setDistance(CommonDrawing::emuToPixels($node->getAttribute('dist'))); - } - // load direction - if ($node->hasAttribute('dir')) { - $effect->setDirection(CommonDrawing::angleToDegrees($node->getAttribute('dir'))); - } - // load alignment - if ($node->hasAttribute('algn')) { - $effect->setAlignment($node->getAttribute('algn')); - } - - // Get color define by prstClr - $oSubElement = $document->getElement('a:prstClr', $node); - if ($oSubElement instanceof \DOMElement && $oSubElement->hasAttribute('val')) { - $oColor = new Color(); - $oColor->setRGB($oSubElement->getAttribute('val')); - $effect->setColor($oColor); - // Get Alpha - $oSubElt = $document->getElement('a:alpha', $oSubElement); - if ($oSubElt instanceof \DOMElement && $oSubElt->hasAttribute('val')) { - $effect->setAlpha((int)$oSubElt->getAttribute('val') / 1000); - } - } - // Load reflection atributs -// @TODO future implementation - if ($node->tagName == 'a:reflection') { - } - - if (!isset($aEffect)) $aEffect = array(); - $aEffect[] = $effect; - } - } - } - return $aEffect; + if ($node instanceof DOMElement) { + $aNodes = $document->getElements('*', $node); + foreach ($aNodes as $nodeShadow) { + $type = explode(':', $nodeShadow->tagName); + $type = array_pop($type); + if ($type == Shadow::TYPE_SHADOW_INNER || $type == Shadow::TYPE_SHADOW_OUTER || $type == Shadow::TYPE_REFLECTION) { + $oShadow = new Shadow(); + $oShadow->setVisible(true); + $oShadow->setType($type); + if ($nodeShadow->hasAttribute('blurRad')) { + $oShadow->setBlurRadius(CommonDrawing::emuToPixels((int) $nodeShadow->getAttribute('blurRad'))); + } + if ($nodeShadow->hasAttribute('dist')) { + $oShadow->setDistance(CommonDrawing::emuToPixels((int) $nodeShadow->getAttribute('dist'))); + } + if ($nodeShadow->hasAttribute('dir')) { + $oShadow->setDirection((int) CommonDrawing::angleToDegrees((int) $nodeShadow->getAttribute('dir'))); + } + if ($nodeShadow->hasAttribute('algn')) { + $oShadow->setAlignment($node->getAttribute('algn')); + } + + // Get color define by prstClr + $oSubElement = $document->getElement('a:prstClr', $nodeShadow); + if ($oSubElement instanceof DOMElement && $oSubElement->hasAttribute('val')) { + $oColor = new Color(); + $oColor->setRGB($oSubElement->getAttribute('val')); + + $oSubElt = $document->getElement('a:alpha', $oSubElement); + if ($oSubElt instanceof DOMElement && $oSubElt->hasAttribute('val')) { + $oColor->setAlpha((int) $oSubElt->getAttribute('val') / 1000); + } + + $oShadow->setColor($oColor); + } + + return $oShadow; + } + } + } + + return null; } /** @@ -967,8 +947,9 @@ protected function loadShapeRichText(XMLReader $document, DOMElement $node, $oSl } $oElement = $document->getElement('p:nvSpPr/p:cNvPr', $node); - if ($oElement instanceof \DOMElement) + if ($oElement instanceof DOMElement) { $oShape->setName($oElement->hasAttribute('name') ? $oElement->getAttribute('name') : ''); + } $oElement = $document->getElement('p:spPr/a:xfrm', $node); if ($oElement instanceof DOMElement && $oElement->hasAttribute('rot')) { @@ -1004,33 +985,31 @@ protected function loadShapeRichText(XMLReader $document, DOMElement $node, $oSl } // Load shape effects - $oEffect = $document->getElement('p:spPr/a:effectLst', $node); - if ($oEffect instanceof \DOMElement) { - $aEffect = $this->loadEffect($document, $oEffect); - if (isset($aEffect) && is_array($aEffect)) { - $oShape->setEffectCollection($aEffect); - } + $oElement = $document->getElement('p:spPr/a:effectLst', $node); + if ($oElement instanceof DOMElement) { + $oShape->setShadow( + $this->loadShadow($document, $oElement) + ); } -// FBU-20210202+ Read body definitions + // FBU-20210202+ Read body definitions $bodyPr = $document->getElement('p:txBody/a:bodyPr', $node); - if (($bodyPr instanceof \DOMElement) && $bodyPr->hasAttribute('lIns')) { - $oShape->setInsetLeft((int)$bodyPr->getAttribute('lIns')); - } - if (($bodyPr instanceof \DOMElement) && $bodyPr->hasAttribute('tIns')) { - $oShape->setInsetTop((int)$bodyPr->getAttribute('tIns')); - } - if (($bodyPr instanceof \DOMElement) && $bodyPr->hasAttribute('rIns')) { - $oShape->setInsetRight((int)$bodyPr->getAttribute('rIns')); - } - if (($bodyPr instanceof \DOMElement) && $bodyPr->hasAttribute('bIns')) { - $oShape->setInsetBottom((int)$bodyPr->getAttribute('bIns')); - } - if (($bodyPr instanceof \DOMElement) && $bodyPr->hasAttribute('anchor')) { - $oShape->setVerticalAlignment($bodyPr->getAttribute('anchor')); - } - if (($bodyPr instanceof \DOMElement) && $bodyPr->hasAttribute('anchorCtr')) { - $oShape->setVerticalAlignCenter((int)$bodyPr->getAttribute('anchorCtr')); + if ($bodyPr instanceof DOMElement) { + if ($bodyPr->hasAttribute('lIns')) { + $oShape->setInsetLeft((int) $bodyPr->getAttribute('lIns')); + } + if ($bodyPr->hasAttribute('tIns')) { + $oShape->setInsetTop((int) $bodyPr->getAttribute('tIns')); + } + if ($bodyPr->hasAttribute('rIns')) { + $oShape->setInsetRight((int) $bodyPr->getAttribute('rIns')); + } + if ($bodyPr->hasAttribute('bIns')) { + $oShape->setInsetBottom((int) $bodyPr->getAttribute('bIns')); + } + if ($bodyPr->hasAttribute('anchorCtr')) { + $oShape->setVerticalAlignCenter((int) $bodyPr->getAttribute('anchorCtr')); + } } $arrayElements = $document->getElements('p:txBody/a:p', $node); @@ -1041,9 +1020,10 @@ protected function loadShapeRichText(XMLReader $document, DOMElement $node, $oSl } $oElement = $document->getElement('p:spPr', $node); - if ($oElement instanceof \DOMElement) { - $oFill = $this->loadStyleFill($document, $oElement); - $oShape->setFill($oFill); + if ($oElement instanceof DOMElement) { + $oShape->setFill( + $this->loadStyleFill($document, $oElement) + ); } if (count($oShape->getParagraphs()) > 0) { @@ -1316,11 +1296,7 @@ protected function loadParagraph(XMLReader $document, DOMElement $oElement, $oSh $oText->setLanguage($oElementrPr->getAttribute('lang')); } if ($oElementrPr->hasAttribute('baseline')) { - if ((int)$oElementrPr->getAttribute('baseline')>0) { - $oText->getFont()->setSuperScript((int)$oElementrPr->getAttribute('baseline')); - } else if ((int)$oElementrPr->getAttribute('baseline')<0) { - $oText->getFont()->setSubScript((int)$oElementrPr->getAttribute('baseline')); - } + $oText->getFont()->setBaseline((int) $oElementrPr->getAttribute('baseline')); } // Color $oElementSrgbClr = $document->getElement('a:solidFill/a:srgbClr', $oElementrPr); @@ -1358,28 +1334,20 @@ protected function loadParagraph(XMLReader $document, DOMElement $oElement, $oSh } // Font definition $oElementFont = $document->getElement('a:latin', $oElementrPr); - if (is_object($oElementFont) && $oElementFont->hasAttribute('typeface')) { - $oText->getFont()->setName($oElementFont->getAttribute('typeface')); - } - if (($oElementFont instanceof \DOMElement) && $oElementFont->hasAttribute('panose')) { - $oText->getFont()->setPanose($oElementFont->getAttribute('panose')); - } - if (($oElementFont instanceof \DOMElement) && $oElementFont->hasAttribute('pitchFamily')) { - $oText->getFont()->setPitchFamily($oElementFont->getAttribute('pitchFamily')); - } - if (($oElementFont instanceof \DOMElement) && $oElementFont->hasAttribute('charset')) { - $oText->getFont()->setCharset($oElementFont->getAttribute('charset')); - } - // Load shape effects - $oEffect = $document->getElement('a:effectLst', $oElementrPr); - if ($oEffect instanceof \DOMElement) { - $aEffect = $this->loadEffect($document, $oEffect); - if (isset($aEffect) && is_array($aEffect)) { - $oText->setEffectCollection($aEffect); - } + if ($oElementFont instanceof DOMElement) { + if ($oElementFont->hasAttribute('typeface')) { + $oText->getFont()->setName($oElementFont->getAttribute('typeface')); + } + if ($oElementFont->hasAttribute('panose')) { + $oText->getFont()->setPanose($oElementFont->getAttribute('panose')); + } + if ($oElementFont->hasAttribute('pitchFamily')) { + $oText->getFont()->setPitchFamily((int) $oElementFont->getAttribute('pitchFamily')); + } + if ($oElementFont->hasAttribute('charset')) { + $oText->getFont()->setCharset((int) $oElementFont->getAttribute('charset')); + } } - //} else { - // $oText = $oParagraph->createText(); $oSubSubElement = $document->getElement('a:t', $oSubElement); $oText->setText($oSubSubElement->nodeValue); diff --git a/src/PhpPresentation/Reader/PowerPoint97.php b/src/PhpPresentation/Reader/PowerPoint97.php index 6189edb08..4ef8fc91c 100644 --- a/src/PhpPresentation/Reader/PowerPoint97.php +++ b/src/PhpPresentation/Reader/PowerPoint97.php @@ -1796,7 +1796,7 @@ private function readRecordOfficeArtSpgrContainer($stream, $pos, $bInGroup = fal $arrayIdxSlide = array_flip($this->arrayNotes); if ($this->currentNote > 0 && isset($arrayIdxSlide[$this->currentNote])) { $oSlide = $this->oPhpPresentation->getSlide($arrayIdxSlide[$this->currentNote]); - if (0 == $oSlide->getNote()->getShapeCollection()->count()) { + if (0 == count($oSlide->getNote()->getShapeCollection())) { $oSlide->getNote()->addShape($fileBlock['shape']); } } diff --git a/src/PhpPresentation/Reader/Serialized.php b/src/PhpPresentation/Reader/Serialized.php index 208c28325..df58d9551 100644 --- a/src/PhpPresentation/Reader/Serialized.php +++ b/src/PhpPresentation/Reader/Serialized.php @@ -92,14 +92,13 @@ private function loadSerialized(string $pFilename): PhpPresentation // Update media links for ($i = 0; $i < $file->getSlideCount(); ++$i) { - for ($j = 0; $j < $file->getSlide($i)->getShapeCollection()->count(); ++$j) { - if ($file->getSlide($i)->getShapeCollection()->offsetGet($j) instanceof AbstractDrawingAdapter) { - $imgTemp = $file->getSlide($i)->getShapeCollection()->offsetGet($j); - $imgPath = 'zip://' . $pFilename . '#media/' . $imgTemp->getImageIndex() . '/' . pathinfo($imgTemp->getPath(), PATHINFO_BASENAME); - if ($imgTemp instanceof DrawingFile) { - $imgTemp->setPath($imgPath, false); + foreach ($file->getSlide($i)->getShapeCollection() as $shape) { + if ($shape instanceof AbstractDrawingAdapter) { + $imgPath = 'zip://' . $pFilename . '#media/' . $shape->getImageIndex() . '/' . pathinfo($shape->getPath(), PATHINFO_BASENAME); + if ($shape instanceof DrawingFile) { + $shape->setPath($imgPath, false); } else { - $imgTemp->setPath($imgPath); + $shape->setPath($imgPath); } } } diff --git a/src/PhpPresentation/Shape/AbstractGraphic.php b/src/PhpPresentation/Shape/AbstractGraphic.php index f8b464f51..064e32a9e 100644 --- a/src/PhpPresentation/Shape/AbstractGraphic.php +++ b/src/PhpPresentation/Shape/AbstractGraphic.php @@ -41,13 +41,6 @@ abstract class AbstractGraphic extends AbstractShape implements ComparableInterf */ private $imageIndex = 0; - /** - * Name. - * - * @var string - */ - protected $name; - /** * Description. * @@ -105,30 +98,6 @@ public function getImageIndex() return $this->imageIndex; } - /** - * Get Name. - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Set Name. - * - * @param string $pValue - * - * @return $this - */ - public function setName($pValue = '') - { - $this->name = $pValue; - - return $this; - } - /** * Get Description. * diff --git a/src/PhpPresentation/Shape/Chart/Legend.php b/src/PhpPresentation/Shape/Chart/Legend.php index 8798ea555..2d31708fc 100644 --- a/src/PhpPresentation/Shape/Chart/Legend.php +++ b/src/PhpPresentation/Shape/Chart/Legend.php @@ -89,21 +89,21 @@ class Legend implements ComparableInterface /** * Border. * - * @var \PhpOffice\PhpPresentation\Style\Border + * @var Border */ private $border; /** * Fill. * - * @var \PhpOffice\PhpPresentation\Style\Fill + * @var Fill */ private $fill; /** * Alignment. * - * @var \PhpOffice\PhpPresentation\Style\Alignment + * @var Alignment */ private $alignment; @@ -133,7 +133,7 @@ public function isVisible() * * @param bool $value * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * @return Legend */ public function setVisible($value = true) { @@ -157,7 +157,7 @@ public function getPosition() * * @param string $value * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * @return Legend */ public function setPosition($value = self::POSITION_RIGHT) { @@ -261,7 +261,7 @@ public function setFont(?Font $pFont = null): self /** * Get Border. * - * @return \PhpOffice\PhpPresentation\Style\Border + * @return Border */ public function getBorder() { @@ -271,7 +271,7 @@ public function getBorder() /** * Set Border. * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * @return Legend */ public function setBorder(Border $border) { @@ -283,7 +283,7 @@ public function setBorder(Border $border) /** * Get Fill. * - * @return \PhpOffice\PhpPresentation\Style\Fill + * @return Fill */ public function getFill() { @@ -293,7 +293,7 @@ public function getFill() /** * Set Fill. * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * @return Legend */ public function setFill(Fill $fill) { @@ -305,7 +305,7 @@ public function setFill(Fill $fill) /** * Get alignment. * - * @return \PhpOffice\PhpPresentation\Style\Alignment + * @return Alignment */ public function getAlignment() { @@ -315,7 +315,7 @@ public function getAlignment() /** * Set alignment. * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Legend + * @return Legend */ public function setAlignment(Alignment $alignment) { diff --git a/src/PhpPresentation/Shape/Chart/Title.php b/src/PhpPresentation/Shape/Chart/Title.php index 69494b785..a06c74468 100644 --- a/src/PhpPresentation/Shape/Chart/Title.php +++ b/src/PhpPresentation/Shape/Chart/Title.php @@ -73,14 +73,14 @@ class Title implements ComparableInterface /** * Alignment. * - * @var \PhpOffice\PhpPresentation\Style\Alignment + * @var Alignment */ private $alignment; /** * Font. * - * @var \PhpOffice\PhpPresentation\Style\Font + * @var Font */ private $font; @@ -117,7 +117,7 @@ public function isVisible() * * @param bool $value * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * @return Title */ public function setVisible($value = true) { @@ -141,7 +141,7 @@ public function getText() * * @param string $value * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * @return Title */ public function setText($value = null) { @@ -245,7 +245,7 @@ public function setFont(?Font $pFont = null): self /** * Get alignment. * - * @return \PhpOffice\PhpPresentation\Style\Alignment + * @return Alignment */ public function getAlignment() { @@ -255,7 +255,7 @@ public function getAlignment() /** * Set alignment. * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Title + * @return Title */ public function setAlignment(Alignment $alignment) { diff --git a/src/PhpPresentation/Shape/Chart/Type/AbstractTypeBar.php b/src/PhpPresentation/Shape/Chart/Type/AbstractTypeBar.php index 751b23371..8b671c74e 100644 --- a/src/PhpPresentation/Shape/Chart/Type/AbstractTypeBar.php +++ b/src/PhpPresentation/Shape/Chart/Type/AbstractTypeBar.php @@ -67,7 +67,7 @@ abstract class AbstractTypeBar extends AbstractType * * @param string $value * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeBar + * @return AbstractTypeBar */ public function setBarDirection($value = self::DIRECTION_VERTICAL) { @@ -91,7 +91,7 @@ public function getBarDirection() * * @param string $value * - * @return \PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeBar + * @return AbstractTypeBar */ public function setBarGrouping($value = self::GROUPING_CLUSTERED) { diff --git a/src/PhpPresentation/Shape/Chart/View3D.php b/src/PhpPresentation/Shape/Chart/View3D.php index b6c0a4996..64111db63 100644 --- a/src/PhpPresentation/Shape/Chart/View3D.php +++ b/src/PhpPresentation/Shape/Chart/View3D.php @@ -97,7 +97,7 @@ public function getRotationX() * * @param int $pValue * - * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D + * @return View3D */ public function setRotationX($pValue = 0) { @@ -121,7 +121,7 @@ public function getRotationY() * * @param int $pValue * - * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D + * @return View3D */ public function setRotationY($pValue = 0) { @@ -145,7 +145,7 @@ public function hasRightAngleAxes() * * @param bool $value * - * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D + * @return View3D */ public function setRightAngleAxes($value = true) { @@ -169,7 +169,7 @@ public function getPerspective() * * @param int $value * - * @return \PhpOffice\PhpPresentation\Shape\Chart\View3D + * @return View3D */ public function setPerspective($value = 30) { diff --git a/src/PhpPresentation/Shape/Drawing/Gd.php b/src/PhpPresentation/Shape/Drawing/Gd.php index 690966608..16fa6fe16 100644 --- a/src/PhpPresentation/Shape/Drawing/Gd.php +++ b/src/PhpPresentation/Shape/Drawing/Gd.php @@ -93,8 +93,8 @@ public function setImageResource($value = null) if (null !== $this->imageResource) { // Get width/height - $this->width = (int)@imagesx($this->imageResource); - $this->height = (int)@imagesy($this->imageResource); + $this->width = imagesx($this->imageResource); + $this->height = imagesy($this->imageResource); } return $this; diff --git a/src/PhpPresentation/Shape/Group.php b/src/PhpPresentation/Shape/Group.php index 4945f1561..1ceaf55e5 100644 --- a/src/PhpPresentation/Shape/Group.php +++ b/src/PhpPresentation/Shape/Group.php @@ -19,19 +19,14 @@ namespace PhpOffice\PhpPresentation\Shape; -use ArrayObject; use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\GeometryCalculator; use PhpOffice\PhpPresentation\ShapeContainerInterface; +use PhpOffice\PhpPresentation\Traits\ShapeCollection; class Group extends AbstractShape implements ShapeContainerInterface { - /** - * Collection of shapes. - * - * @var array|ArrayObject - */ - private $shapeCollection; + use ShapeCollection; /** * Extent X. @@ -50,29 +45,6 @@ class Group extends AbstractShape implements ShapeContainerInterface public function __construct() { parent::__construct(); - - // Shape collection - $this->shapeCollection = new ArrayObject(); - } - - /** - * Get collection of shapes. - * - * @return array|ArrayObject - */ - public function getShapeCollection() - { - return $this->shapeCollection; - } - - /** - * Add shape to slide. - */ - public function addShape(AbstractShape $shape): AbstractShape - { - $shape->setContainer($this); - - return $shape; } /** diff --git a/src/PhpPresentation/Shape/RichText.php b/src/PhpPresentation/Shape/RichText.php index 86f75c924..7aafe3c10 100644 --- a/src/PhpPresentation/Shape/RichText.php +++ b/src/PhpPresentation/Shape/RichText.php @@ -21,6 +21,7 @@ use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\NotAllowedValueException; use PhpOffice\PhpPresentation\Exception\OutOfBoundsException; use PhpOffice\PhpPresentation\Shape\RichText\Paragraph; use PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface; @@ -43,22 +44,17 @@ class RichText extends AbstractShape implements ComparableInterface /** Overflow */ public const OVERFLOW_CLIP = 'clip'; public const OVERFLOW_OVERFLOW = 'overflow'; - - /** Vertical alignment */ - const VALIGN_TOP = 't'; - const VALIGN_MIDDLE = 'ctr'; - const VALIGN_BOTTOM = 'b'; - + /** Vertical alignment center */ - const VALIGN_CENTER = 1; - const VALIGN_NOTCENTER = 0; + public const VALIGN_CENTER = 1; + public const VALIGN_NOTCENTER = 0; /** * Rich text paragraphs. * * @var array */ - private $richTextParagraphs; + private $richTextParagraphs = []; /** * Active paragraph. @@ -178,14 +174,10 @@ class RichText extends AbstractShape implements ComparableInterface * @var null|float */ private $lnSpcReduction; - - /** - * Define vertical text position into shape (top,center,bottom) - * @var string - */ - private $verticalAlign = self::VALIGN_TOP; + /** - * Define vertical text center position into shape (center,not center) + * Define vertical text center position into shape (center,not center). + * * @var int */ private $verticalAlignCenter = self::VALIGN_NOTCENTER; @@ -205,23 +197,20 @@ public function __construct() } /** - * Magic Method : clone + * Magic Method : clone. */ public function __clone() { // Call perent clonage for heritage parent::__clone(); // Clone each paragraph - if (isset($this->richTextParagraphs)) { - foreach ($this->richTextParagraphs as &$paragraph) { + foreach ($this->richTextParagraphs as &$paragraph) { $paragraph = clone $paragraph; - }} + } } /** - * Get active paragraph index - * - * @return int + * Get active paragraph index. */ public function getActiveParagraphIndex(): int { @@ -506,58 +495,34 @@ public function setVertical(bool $value = false): self return $this; } - - /** - * Define the vertical alignment - * - * @param string|null $value top,center,bottom - * @return $this - * @see self::VALIGN_TOP, self::VALIGN_MIDLE, self::VALIGN_BOTTOM - */ - public function setVerticalAlignment(?string $value) - { - if (isset($value)) { - $this->verticalAlign = $value; - } else { - $this->verticalAlign = self::VALIGN_TOP; - } - return $this; - } - - /** - * Get the vertical alignment - * - * @return string - * @see self::VALIGN_TOP, self::VALIGN_MIDLE, self::VALIGN_BOTTOM - */ - public function getVerticalAlignment():string - { - return $this->verticalAlign; - } /** - * Define the vertical alignment if centered or not - * @param int|null $value 1=center 0=not center - * @return $this + * Define the vertical alignment if centered or not. + * + * @param int $value 1=center 0=not + * * @see self::VALIGN_CENTER, self::VALIGN_NOTCENTER */ - public function setVerticalAlignCenter(?int $value) + public function setVerticalAlignCenter(int $value): self { - if (isset($value)) { + if (!in_array( + $value, + [self::VALIGN_CENTER, self::VALIGN_NOTCENTER] + )) { + throw new NotAllowedValueException((string) $value, [(string) self::VALIGN_CENTER, (string) self::VALIGN_NOTCENTER]); + } + $this->verticalAlignCenter = $value; - } else { - $this->verticalAlignCenter = self::VALIGN_NOTCENTER; - } - return $this; + + return $this; } /** - * Get the vertical alignment center - * @return int + * Get the vertical alignment center. */ - public function getVerticalAlignCenter():int + public function getVerticalAlignCenter(): int { - return $this->verticalAlignCenter; + return $this->verticalAlignCenter; } /** @@ -730,6 +695,7 @@ public function getHashCode(): string . $this->leftInset . $this->rightInset . $this->topInset + . $this->verticalAlignCenter . parent::getHashCode() . __CLASS__ ); diff --git a/src/PhpPresentation/Shape/RichText/Paragraph.php b/src/PhpPresentation/Shape/RichText/Paragraph.php index 95c9004ce..66b3519a3 100644 --- a/src/PhpPresentation/Shape/RichText/Paragraph.php +++ b/src/PhpPresentation/Shape/RichText/Paragraph.php @@ -66,13 +66,7 @@ class Paragraph implements ComparableInterface private $lineSpacing = 100; /** - * List of effect apply to paragraph - * @var array \PhpOffice\PhpPresentation\Style\Effect[] - */ - protected ?array $effectCollection = null; - - /** - * Hash index + * Hash index. * * @var string */ @@ -103,30 +97,21 @@ public function __construct() $this->alignment = new Alignment(); $this->font = new Font(); $this->bulletStyle = new Bullet(); - $this->effectCollection = null; } /** - * Magic Method : clone + * Magic Method : clone. */ public function __clone() { - // Clone each text - if (isset($this->richTextElements)) { - foreach ($this->richTextElements as &$txtElt) { - $txtElt = clone $txtElt; - }} - // Clone each effect - if (isset($this->effectCollection)) { - foreach ($this->effectCollection as &$effect) { - $effect = clone $effect; - }} + // Clone each text + foreach ($this->richTextElements as &$rtElement) { + $rtElement = clone $rtElement; + } } /** - * Get alignment - * - * @return \PhpOffice\PhpPresentation\Style\Alignment + * Get alignment. */ public function getAlignment(): Alignment { @@ -283,47 +268,7 @@ public function setRichTextElements(array $pElements = []): self } /** - * Add an effect to the shpae - * - * @param \PhpOffice\PhpPresentation\Style\Effect $effect - * @return $this - */ - public function addEffect(Shape\Effect $effect) - { - if (!isset($this->effectCollection)) { - $this->effectCollection = array(); - } - $this->effectCollection[] = $effect; - return $this; - } - - /** - * Get the effect collection - * - * @return array \PhpOffice\PhpPresentation\Style\Effect[] - */ - public function getEffectCollection():?array - { - return $this->effectCollection; - } - - /** - * Set the effect collection - * - * @param array \PhpOffice\PhpPresentation\Style\Effect $effectCollection - * @return $this - */ - public function setEffectCollection(array $effectCollection) - { - if ( isset($effectCollection) - && is_array($effectCollection)) { - $this->effectCollection = $effectCollection; - } - return $this; - } - - /** - * Get hash code + * Get hash code. * * @return string Hash code */ diff --git a/src/PhpPresentation/Shape/RichText/Run.php b/src/PhpPresentation/Shape/RichText/Run.php index e4528acb6..a9f99fe3e 100644 --- a/src/PhpPresentation/Shape/RichText/Run.php +++ b/src/PhpPresentation/Shape/RichText/Run.php @@ -29,27 +29,18 @@ class Run extends TextElement implements TextElementInterface /** * Font. * - * @var \PhpOffice\PhpPresentation\Style\Font + * @var Font */ private $font; /** - * List of effect apply to paragraph - * @var array \PhpOffice\PhpPresentation\Style\Effect[] - */ - protected ?array $effectCollection = null; - - /** - * Create a new \PhpOffice\PhpPresentation\Shape\RichText\Run instance - * * @param string $pText Text */ public function __construct($pText = '') { - // Initialise variables + // Initialize variables $this->setText($pText); $this->font = new Font(); - $this->effectCollection = null; } /** @@ -63,9 +54,7 @@ public function getFont(): Font /** * Set font. * - * @param null|Font $pFont Font - * - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface + * @return self */ public function setFont(?Font $pFont = null) { @@ -75,49 +64,7 @@ public function setFont(?Font $pFont = null) } /** - * Add an effect to the shpae - * - * @param \PhpOffice\PhpPresentation\Style\Effect $effect - * @return $this - */ - public function addEffect(Shape\Effect $effect) - { - if (!isset($this->effectCollection)) { - $this->effectCollection = array(); - } - $this->effectCollection[] = $effect; - return $this; - } - - /** - * Get the effect collection - * - * @return array \PhpOffice\PhpPresentation\Style\Effect[] - */ - public function getEffectCollection():?array - { - return $this->effectCollection; - } - - /** - * Set the effect collection - * - * @param array \PhpOffice\PhpPresentation\Style\Effect $effectCollection - * @return $this - */ - public function setEffectCollection(array $effectCollection) - { - if ( isset($effectCollection) - && is_array($effectCollection)) { - $this->effectCollection = $effectCollection; - } - return $this; - } - - /** - * Get hash code - * - * @return string Hash code + * Get hash code. */ public function getHashCode(): string { diff --git a/src/PhpPresentation/Shape/RichText/TextElement.php b/src/PhpPresentation/Shape/RichText/TextElement.php index 709860ffb..e240a01e2 100644 --- a/src/PhpPresentation/Shape/RichText/TextElement.php +++ b/src/PhpPresentation/Shape/RichText/TextElement.php @@ -72,7 +72,7 @@ public function getText() * * @param string $pText Text value * - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface + * @return TextElementInterface */ public function setText($pText = '') { @@ -106,7 +106,7 @@ public function getHyperlink(): Hyperlink /** * Set Hyperlink. * - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElement + * @return TextElement */ public function setHyperlink(?Hyperlink $pHyperlink = null) { diff --git a/src/PhpPresentation/Shape/RichText/TextElementInterface.php b/src/PhpPresentation/Shape/RichText/TextElementInterface.php index af2485bb0..f0edad48c 100644 --- a/src/PhpPresentation/Shape/RichText/TextElementInterface.php +++ b/src/PhpPresentation/Shape/RichText/TextElementInterface.php @@ -36,7 +36,7 @@ public function getText(); * * @param string $pText Text value * - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface + * @return TextElementInterface */ public function setText($pText = ''); @@ -55,7 +55,7 @@ public function getLanguage(); /** * @param string $lang * - * @return \PhpOffice\PhpPresentation\Shape\RichText\TextElementInterface + * @return TextElementInterface */ public function setLanguage($lang); diff --git a/src/PhpPresentation/Shape/Table/Cell.php b/src/PhpPresentation/Shape/Table/Cell.php index 47bf1e6e6..d5e5251c8 100644 --- a/src/PhpPresentation/Shape/Table/Cell.php +++ b/src/PhpPresentation/Shape/Table/Cell.php @@ -48,14 +48,14 @@ class Cell implements ComparableInterface /** * Fill. * - * @var \PhpOffice\PhpPresentation\Style\Fill + * @var Fill */ private $fill; /** * Borders. * - * @var \PhpOffice\PhpPresentation\Style\Borders + * @var Borders */ private $borders; @@ -178,7 +178,7 @@ public function createParagraph(): Paragraph * * @param TextElementInterface $pText Rich text element * - * @return \PhpOffice\PhpPresentation\Shape\Table\Cell + * @return Cell */ public function addText(?TextElementInterface $pText = null) { @@ -276,7 +276,7 @@ public function setParagraphs(array $paragraphs = []): self /** * Get fill. * - * @return \PhpOffice\PhpPresentation\Style\Fill + * @return Fill */ public function getFill() { @@ -286,7 +286,7 @@ public function getFill() /** * Set fill. * - * @return \PhpOffice\PhpPresentation\Shape\Table\Cell + * @return Cell */ public function setFill(Fill $fill) { @@ -298,7 +298,7 @@ public function setFill(Fill $fill) /** * Get borders. * - * @return \PhpOffice\PhpPresentation\Style\Borders + * @return Borders */ public function getBorders() { @@ -308,7 +308,7 @@ public function getBorders() /** * Set borders. * - * @return \PhpOffice\PhpPresentation\Shape\Table\Cell + * @return Cell */ public function setBorders(Borders $borders) { diff --git a/src/PhpPresentation/ShapeContainerInterface.php b/src/PhpPresentation/ShapeContainerInterface.php index a347c358e..5fde0573d 100644 --- a/src/PhpPresentation/ShapeContainerInterface.php +++ b/src/PhpPresentation/ShapeContainerInterface.php @@ -36,10 +36,17 @@ public function getShapeCollection(); /** * Add shape to slide. * - * @return AbstractShape + * @return static */ public function addShape(AbstractShape $shape); + /** + * Unset shape from the collection. + * + * @return static + */ + public function unsetShape(int $key); + /** * Get X Offset. */ diff --git a/src/PhpPresentation/Slide.php b/src/PhpPresentation/Slide.php index 150e14426..3b0a9218f 100644 --- a/src/PhpPresentation/Slide.php +++ b/src/PhpPresentation/Slide.php @@ -19,7 +19,6 @@ namespace PhpOffice\PhpPresentation; -use ArrayObject; use PhpOffice\PhpPresentation\Slide\AbstractSlide; use PhpOffice\PhpPresentation\Slide\Note; use PhpOffice\PhpPresentation\Slide\SlideLayout; @@ -74,8 +73,6 @@ public function __construct(?PhpPresentation $pParent = null) { // Set parent $this->parent = $pParent; - // Shape collection - $this->shapeCollection = new ArrayObject(); // Set identifier $this->identifier = md5(mt_rand(0, mt_getrandmax()) . time()); // Set Slide Layout @@ -123,7 +120,7 @@ public function getSlideMasterId() * * @param int $masterId * - * @return \PhpOffice\PhpPresentation\Slide + * @return Slide */ public function setSlideMasterId($masterId = 1) { @@ -132,33 +129,26 @@ public function setSlideMasterId($masterId = 1) return $this; } - public function __clone() { - // Set parent - $this->parent = clone $this->parent; - // Shape collection - if (isset($this->shapeCollection)) { - $this->shapeCollection = clone $this->shapeCollection; + // Set parent + $this->parent = clone $this->parent; + // Shape collection foreach ($this->shapeCollection as &$shape) { - $shape = clone $shape; + $shape = clone $shape; + } + // Transition + if (isset($this->slideTransition)) { + $this->slideTransition = clone $this->slideTransition; } - } - // Transition object - if (isset($this->slideTransition)) { - $this->slideTransition = clone $this->slideTransition; - } - // Note object - if (isset($this->slideNote)) { + // Note $this->slideNote = clone $this->slideNote; - } - } /** * Copy slide (!= clone!). * - * @return \PhpOffice\PhpPresentation\Slide + * @return Slide */ public function copy() { @@ -221,7 +211,7 @@ public function setIsVisible($value = true) /** * Add an animation to the slide. * - * @param \PhpOffice\PhpPresentation\Slide\Animation $animation + * @param Slide\Animation $animation * * @return Slide */ diff --git a/src/PhpPresentation/Slide/AbstractSlide.php b/src/PhpPresentation/Slide/AbstractSlide.php index d67d51b16..9c93c3283 100644 --- a/src/PhpPresentation/Slide/AbstractSlide.php +++ b/src/PhpPresentation/Slide/AbstractSlide.php @@ -19,8 +19,6 @@ namespace PhpOffice\PhpPresentation\Slide; -use ArrayObject; -use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\ComparableInterface; use PhpOffice\PhpPresentation\GeometryCalculator; use PhpOffice\PhpPresentation\PhpPresentation; @@ -31,9 +29,12 @@ use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\Shape\Table; use PhpOffice\PhpPresentation\ShapeContainerInterface; +use PhpOffice\PhpPresentation\Traits\ShapeCollection; abstract class AbstractSlide implements ComparableInterface, ShapeContainerInterface { + use ShapeCollection; + /** * @var string */ @@ -44,13 +45,6 @@ abstract class AbstractSlide implements ComparableInterface, ShapeContainerInter */ protected $slideTransition; - /** - * Collection of shapes. - * - * @var array|ArrayObject - */ - protected $shapeCollection = []; - /** * Extent Y. * @@ -107,56 +101,6 @@ abstract class AbstractSlide implements ComparableInterface, ShapeContainerInter */ protected $background; - /** - * Get collection of shapes. - * - * @return array|ArrayObject - */ - public function getShapeCollection() - { - return $this->shapeCollection; - } - - /** - * Search into collection of shapes for a name (eventually filtered by type ex: RichText) - * - * @param string $name The name to find into the shape collection - * @param PhpOffice\PhpPresentation\Shape\RichText | PhpOffice\PhpPresentation\Shape\... $type Type of the class - * @return \ArrayObject|\PhpOffice\PhpPresentation\AbstractShape[] - */ - public function searchShapeByName(string $name, ?string $type=null) - { - if (isset($this->shapeCollection)) { - foreach ($this->shapeCollection as $shape) { - if ($shape->getName() == $name) { - if (!isset($type) || get_class($shape) == $type) { - return $shape; - }}}} - return null; - } - - /** - * Get collection of shapes - * - * @return AbstractSlide - */ - public function setShapeCollection($shapeCollection = []) - { - $this->shapeCollection = $shapeCollection; - - return $this; - } - - /** - * Add shape to slide. - */ - public function addShape(AbstractShape $shape): AbstractShape - { - $shape->setContainer($this); - - return $shape; - } - /** * Get X Offset. */ diff --git a/src/PhpPresentation/Slide/Animation.php b/src/PhpPresentation/Slide/Animation.php index f5215ac2a..e32a4c71b 100644 --- a/src/PhpPresentation/Slide/Animation.php +++ b/src/PhpPresentation/Slide/Animation.php @@ -19,42 +19,9 @@ namespace PhpOffice\PhpPresentation\Slide; -use PhpOffice\PhpPresentation\AbstractShape; +use PhpOffice\PhpPresentation\Traits\ShapeCollection; class Animation { - /** - * @var array - */ - protected $shapeCollection = []; - - /** - * @return Animation - */ - public function addShape(AbstractShape $shape) - { - $this->shapeCollection[] = $shape; - - return $this; - } - - /** - * @return array - */ - public function getShapeCollection(): array - { - return $this->shapeCollection; - } - - /** - * @param array $array - * - * @return Animation - */ - public function setShapeCollection(array $array = []) - { - $this->shapeCollection = $array; - - return $this; - } + use ShapeCollection; } diff --git a/src/PhpPresentation/Slide/Iterator.php b/src/PhpPresentation/Slide/Iterator.php index 2b621b7ff..f718728ec 100644 --- a/src/PhpPresentation/Slide/Iterator.php +++ b/src/PhpPresentation/Slide/Iterator.php @@ -21,6 +21,7 @@ use IteratorIterator; use PhpOffice\PhpPresentation\PhpPresentation; +use ReturnTypeWillChange; // @phpstan-ignore-next-line class Iterator extends IteratorIterator @@ -50,7 +51,7 @@ public function __construct(PhpPresentation $subject) /** * Rewind iterator. */ - #[\ReturnTypeWillChange] + #[ReturnTypeWillChange] public function rewind(): void { $this->position = 0; @@ -61,7 +62,7 @@ public function rewind(): void * * @return \PhpOffice\PhpPresentation\Slide */ - #[\ReturnTypeWillChange] + #[ReturnTypeWillChange] public function current() { return $this->subject->getSlide($this->position); @@ -72,7 +73,7 @@ public function current() * * @return int */ - #[\ReturnTypeWillChange] + #[ReturnTypeWillChange] public function key() { return $this->position; @@ -81,7 +82,7 @@ public function key() /** * Next value. */ - #[\ReturnTypeWillChange] + #[ReturnTypeWillChange] public function next(): void { ++$this->position; @@ -92,7 +93,7 @@ public function next(): void * * @return bool */ - #[\ReturnTypeWillChange] + #[ReturnTypeWillChange] public function valid() { return $this->position < $this->subject->getSlideCount(); diff --git a/src/PhpPresentation/Slide/Note.php b/src/PhpPresentation/Slide/Note.php index d60542813..b7a323c67 100644 --- a/src/PhpPresentation/Slide/Note.php +++ b/src/PhpPresentation/Slide/Note.php @@ -19,16 +19,17 @@ namespace PhpOffice\PhpPresentation\Slide; -use ArrayObject; -use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\ComparableInterface; use PhpOffice\PhpPresentation\GeometryCalculator; use PhpOffice\PhpPresentation\Shape\RichText; use PhpOffice\PhpPresentation\ShapeContainerInterface; use PhpOffice\PhpPresentation\Slide; +use PhpOffice\PhpPresentation\Traits\ShapeCollection; class Note implements ComparableInterface, ShapeContainerInterface { + use ShapeCollection; + /** * Parent slide. * @@ -36,13 +37,6 @@ class Note implements ComparableInterface, ShapeContainerInterface */ private $parent; - /** - * Collection of shapes. - * - * @var array|ArrayObject - */ - private $shapeCollection; - /** * Note identifier. * @@ -93,33 +87,10 @@ public function __construct(?Slide $pParent = null) // Set parent $this->parent = $pParent; - // Shape collection - $this->shapeCollection = new ArrayObject(); - // Set identifier $this->identifier = md5(mt_rand(0, 9999) . time()); } - /** - * Get collection of shapes. - * - * @return array|ArrayObject - */ - public function getShapeCollection() - { - return $this->shapeCollection; - } - - /** - * Add shape to slide. - */ - public function addShape(AbstractShape $shape): AbstractShape - { - $shape->setContainer($this); - - return $shape; - } - /** * Create rich text shape. */ diff --git a/src/PhpPresentation/Slide/SlideLayout.php b/src/PhpPresentation/Slide/SlideLayout.php index 6393ca7e2..24c34544b 100644 --- a/src/PhpPresentation/Slide/SlideLayout.php +++ b/src/PhpPresentation/Slide/SlideLayout.php @@ -19,7 +19,6 @@ namespace PhpOffice\PhpPresentation\Slide; -use ArrayObject; use PhpOffice\PhpPresentation\ComparableInterface; use PhpOffice\PhpPresentation\ShapeContainerInterface; use PhpOffice\PhpPresentation\Style\ColorMap; @@ -62,7 +61,7 @@ class SlideLayout extends AbstractSlide implements ComparableInterface, ShapeCon /** * Mapping of colors to the theme. * - * @var \PhpOffice\PhpPresentation\Style\ColorMap + * @var ColorMap */ public $colorMap; @@ -73,8 +72,6 @@ public function __construct(SlideMaster $pSlideMaster) { // Set parent $this->slideMaster = $pSlideMaster; - // Shape collection - $this->shapeCollection = new ArrayObject(); // Set identifier $this->identifier = md5(mt_rand(0, 9999) . time()); // Set a basic colorMap diff --git a/src/PhpPresentation/Slide/SlideMaster.php b/src/PhpPresentation/Slide/SlideMaster.php index 9d877d3f2..1d30e539a 100644 --- a/src/PhpPresentation/Slide/SlideMaster.php +++ b/src/PhpPresentation/Slide/SlideMaster.php @@ -19,7 +19,6 @@ namespace PhpOffice\PhpPresentation\Slide; -use ArrayObject; use PhpOffice\PhpPresentation\ComparableInterface; use PhpOffice\PhpPresentation\PhpPresentation; use PhpOffice\PhpPresentation\ShapeContainerInterface; @@ -80,8 +79,6 @@ public function __construct(?PhpPresentation $pParent = null) { // Set parent $this->parent = $pParent; - // Shape collection - $this->shapeCollection = new ArrayObject(); // Set identifier $this->identifier = md5(mt_rand(0, 9999) . time()); // Set a basic colorMap diff --git a/src/PhpPresentation/Style/Borders.php b/src/PhpPresentation/Style/Borders.php index efdc2867b..f2aefa5b8 100644 --- a/src/PhpPresentation/Style/Borders.php +++ b/src/PhpPresentation/Style/Borders.php @@ -29,42 +29,42 @@ class Borders implements ComparableInterface /** * Left. * - * @var \PhpOffice\PhpPresentation\Style\Border + * @var Border */ private $left; /** * Right. * - * @var \PhpOffice\PhpPresentation\Style\Border + * @var Border */ private $right; /** * Top. * - * @var \PhpOffice\PhpPresentation\Style\Border + * @var Border */ private $top; /** * Bottom. * - * @var \PhpOffice\PhpPresentation\Style\Border + * @var Border */ private $bottom; /** * Diagonal up. * - * @var \PhpOffice\PhpPresentation\Style\Border + * @var Border */ private $diagonalUp; /** * Diagonal down. * - * @var \PhpOffice\PhpPresentation\Style\Border + * @var Border */ private $diagonalDown; @@ -94,7 +94,7 @@ public function __construct() /** * Get Left. * - * @return \PhpOffice\PhpPresentation\Style\Border + * @return Border */ public function getLeft() { @@ -104,7 +104,7 @@ public function getLeft() /** * Get Right. * - * @return \PhpOffice\PhpPresentation\Style\Border + * @return Border */ public function getRight() { @@ -114,7 +114,7 @@ public function getRight() /** * Get Top. * - * @return \PhpOffice\PhpPresentation\Style\Border + * @return Border */ public function getTop() { @@ -124,7 +124,7 @@ public function getTop() /** * Get Bottom. * - * @return \PhpOffice\PhpPresentation\Style\Border + * @return Border */ public function getBottom() { @@ -134,7 +134,7 @@ public function getBottom() /** * Get Diagonal Up. * - * @return \PhpOffice\PhpPresentation\Style\Border + * @return Border */ public function getDiagonalUp() { @@ -144,7 +144,7 @@ public function getDiagonalUp() /** * Get Diagonal Down. * - * @return \PhpOffice\PhpPresentation\Style\Border + * @return Border */ public function getDiagonalDown() { diff --git a/src/PhpPresentation/Style/Bullet.php b/src/PhpPresentation/Style/Bullet.php index e31a06c55..1222cc1f4 100644 --- a/src/PhpPresentation/Style/Bullet.php +++ b/src/PhpPresentation/Style/Bullet.php @@ -149,7 +149,7 @@ public function getBulletType() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\Style\Bullet + * @return Bullet */ public function setBulletType($pValue = self::TYPE_NONE) { @@ -173,7 +173,7 @@ public function getBulletFont() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\Style\Bullet + * @return Bullet */ public function setBulletFont($pValue = 'Calibri') { @@ -200,7 +200,7 @@ public function getBulletChar() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\Style\Bullet + * @return Bullet */ public function setBulletChar($pValue = '-') { @@ -224,7 +224,7 @@ public function getBulletNumericStyle() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\Style\Bullet + * @return Bullet */ public function setBulletNumericStyle($pValue = self::NUMERIC_DEFAULT) { @@ -248,7 +248,7 @@ public function getBulletNumericStartAt() * * @param int|string $pValue * - * @return \PhpOffice\PhpPresentation\Style\Bullet + * @return Bullet */ public function setBulletNumericStartAt($pValue = 1) { diff --git a/src/PhpPresentation/Style/Color.php b/src/PhpPresentation/Style/Color.php index a10ffdc73..6e1f54da6 100644 --- a/src/PhpPresentation/Style/Color.php +++ b/src/PhpPresentation/Style/Color.php @@ -78,7 +78,7 @@ public function getARGB() * * @param string $pValue * - * @return \PhpOffice\PhpPresentation\Style\Color + * @return Color */ public function setARGB($pValue = self::COLOR_BLACK) { @@ -146,7 +146,7 @@ public function getRGB() * @param string $pValue * @param string $pAlpha * - * @return \PhpOffice\PhpPresentation\Style\Color + * @return Color */ public function setRGB($pValue = '000000', $pAlpha = 'FF') { diff --git a/src/PhpPresentation/Style/Effect.php b/src/PhpPresentation/Style/Effect.php deleted file mode 100644 index 5c25ca4f4..000000000 --- a/src/PhpPresentation/Style/Effect.php +++ /dev/null @@ -1,310 +0,0 @@ -effectType = $type; - $this->blurRadius = 6; - $this->distance = 2; - $this->direction = 0; - $this->alignment = self::SHADOW_BOTTOM_RIGHT; - $this->color = new Color(Color::COLOR_BLACK); - $this->alpha = 50; - } - - /** - * Define the type effect - * - * @param string $type - * @return $this - * @see self::EFFECT_SHADOW_INNER, self::EFFECT_SHADOW_OUTER, self::EFFECT_REFLECTION - */ - public function setEffectType(string $type) - { - $this->effectType = $type; - return $this; - } - - /** - * Get the effect type - * - * @return string - */ - public function getEffectType():string - { - return $this->effectType; - } - - /** - * Set the direction - * - * @param int $dir - * @return $this - */ - public function setDirection(?int $dir) - { - if (!isset($dir)) $dir = 0; - $this->direction = (int)$dir; - return $this; - } - - /** - * Get the direction - * - * @return int - */ - public function getDirection():int - { - return $this->direction; - } - - /** - * Set the blur radius - * - * @param int $radius - * @return $this - */ - public function setBlurRadius(?int $radius) - { - if (!isset($radius)) $radius = 6; - $this->blurRadius = $radius; - return $this; - } - - /** - * Get the blur radius - * - * @return int - */ - public function getBlurRadius():int - { - return $this->blurRadius; - } - - /** - * Get Shadow distance - * - * @return int - */ - public function getDistance():int - { - return $this->distance; - } - - /** - * Set Shadow distance - * - * @param int $distance - * @return $this - */ - public function setDistance(int $distance = 2) - { - $this->distance = $distance; - - return $this; - } - - /** - * Set the effect alignment - * - * @param string $align - * @return $this - */ - public function setAlignment(?string $align) - { - if (!isset($align)) $align = self::SHADOW_BOTTOM_RIGHT; - $this->align = $align; - return $this; - } - - /** - * Get the effect alignment - * - * @return string - */ - public function getAlignment():string - { - return $this->align; - } - - /** - * Set Color - * - * @param \PhpOffice\PhpPresentation\Style\Color $color - * @return $this - */ - public function setColor(Color $color = null) - { - $this->color = $color; - - return $this; - } - - /** - * Get Color - * - * @return \PhpOffice\PhpPresentation\Style\Color - */ - public function getColor() - { - return $this->color; - } - - /** - * Set Alpha - * - * @param int $alpha - * @return $this - */ - public function setAlpha(?int $alpha) - { - if (!isset($alpha)) $alpha = 0; - $this->alpha = $alpha; - - return $this; - } - - /** - * Get Alpha - * - * @return int - */ - public function getAlpha():int - { - return $this->alpha; - } - - /** - * Get hash code - * - * @return string Hash code - */ - public function getHashCode() - { - return md5($this->effectType . $this->blurRadius . $this->distance . $this->direction . $this->alignment . $this->color->getHashCode() . $this->alpha . __CLASS__); - } - - /** - * Get hash index - * - * Note that this index may vary during script execution! Only reliable moment is - * while doing a write of a workbook and when changes are not allowed. - * - * @return string Hash index - */ - public function getHashIndex() - { - return $this->hashIndex; - } - - /** - * Set hash index - * - * Note that this index may vary during script execution! Only reliable moment is - * while doing a write of a workbook and when changes are not allowed. - * - * @param string $value Hash index - */ - public function setHashIndex($value) - { - $this->hashIndex = $value; - } - -} diff --git a/src/PhpPresentation/Style/Font.php b/src/PhpPresentation/Style/Font.php index 474d3e0e3..2975df4ef 100644 --- a/src/PhpPresentation/Style/Font.php +++ b/src/PhpPresentation/Style/Font.php @@ -20,6 +20,7 @@ namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\InvalidParameterException; use PhpOffice\PhpPresentation\Exception\NotAllowedValueException; /** @@ -27,6 +28,24 @@ */ class Font implements ComparableInterface { + // Capitalization type + public const CAPITALIZATION_NONE = 'none'; + public const CAPITALIZATION_SMALL = 'small'; + public const CAPITALIZATION_ALL = 'all'; + + // Charset type + public const CHARSET_DEFAULT = 0x01; + + // Format type + public const FORMAT_LATIN = 'latin'; + public const FORMAT_EAST_ASIAN = 'ea'; + public const FORMAT_COMPLEX_SCRIPT = 'cs'; + + // Strike type + public const STRIKE_NONE = 'noStrike'; + public const STRIKE_SINGLE = 'sngStrike'; + public const STRIKE_DOUBLE = 'dblStrike'; + // Underline types public const UNDERLINE_NONE = 'none'; public const UNDERLINE_DASH = 'dash'; @@ -46,23 +65,10 @@ class Font implements ComparableInterface public const UNDERLINE_WAVYDOUBLE = 'wavyDbl'; public const UNDERLINE_WAVYHEAVY = 'wavyHeavy'; public const UNDERLINE_WORDS = 'words'; - - /* Strike types */ - public const STRIKE_NONE = 'noStrike'; - public const STRIKE_SINGLE = 'sngStrike'; - public const STRIKE_DOUBLE = 'dblStrike'; - public const FORMAT_LATIN = 'latin'; - public const FORMAT_EAST_ASIAN = 'ea'; - public const FORMAT_COMPLEX_SCRIPT = 'cs'; - - public const CAPITALIZATION_NONE = 'none'; - public const CAPITALIZATION_SMALL = 'small'; - public const CAPITALIZATION_ALL = 'all'; - - /* Script sub and super values */ - const SCRIPT_SUPER = 30000; - const SCRIPT_SUB = -25000; + // Script sub and super values + public const BASELINE_SUPERSCRIPT = 300000; + public const BASELINE_SUBSCRIPT = -250000; /** * Name. @@ -72,26 +78,28 @@ class Font implements ComparableInterface private $name = 'Calibri'; /** - * panose + * Panose. * * @var string */ - private $panose; + private $panose = ''; + /** - * pitchFamily + * Pitch Family. * - * @var string + * @var int */ - private $pitchFamily; + private $pitchFamily = 0; + /** - * charset + * Charset. * - * @var string + * @var int */ - private $charset; - + private $charset = self::CHARSET_DEFAULT; + /** - * Font Size + * Font Size. * * @var int */ @@ -112,18 +120,11 @@ class Font implements ComparableInterface private $italic = false; /** - * Superscript. - * - * @var bool - */ - private $superScript = false; - - /** - * Subscript. + * Baseline. * - * @var bool + * @var int */ - private $subScript = false; + private $baseline = 0; /** * Capitalization. @@ -142,9 +143,9 @@ class Font implements ComparableInterface /** * Strikethrough. * - * @var bool + * @var string */ - private $strikethrough = false; + private $strikethrough = self::STRIKE_NONE; /** * Foreground color. @@ -177,9 +178,6 @@ class Font implements ComparableInterface public function __construct() { $this->color = new Color(Color::COLOR_BLACK); - $this->superScript = 0; - $this->subScript = 0; - $this->strikethrough = self::STRIKE_NONE; } /** @@ -199,80 +197,74 @@ public function setName(string $pValue = 'Calibri'): self $pValue = 'Calibri'; } $this->name = $pValue; + return $this; } - + /** - * Get panose - * - * @return string + * Get panose. */ - public function getPanose() + public function getPanose(): string { return $this->panose; } /** - * Set panose - * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Set panose. */ - public function setPanose($pValue) + public function setPanose(string $pValue): self { - if ($pValue == '') { - $pValue = ''; + if (mb_strlen($pValue) !== 10) { + throw new InvalidParameterException('pValue', $pValue, 'The length is not equals to 10'); } + + $allowedChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; + foreach (mb_str_split($pValue) as $char) { + if (!in_array($char, $allowedChars)) { + throw new InvalidParameterException( + 'pValue', + $pValue, + sprintf('The character "%s" is not allowed', $char) + ); + } + } + $this->panose = $pValue; return $this; } + /** - * Get pitchFamily - * - * @return string + * Get pitchFamily. */ - public function getPitchFamily() + public function getPitchFamily(): int { return $this->pitchFamily; } /** - * Set pitchFamily - * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Set pitchFamily. */ - public function setPitchFamily($pValue) + public function setPitchFamily(int $pValue): self { - if ($pValue == '') { - $pValue = ''; - } $this->pitchFamily = $pValue; return $this; } + /** - * Get charset - * - * @return string + * Get charset. */ - public function getCharset() + public function getCharset(): int { return $this->charset; } /** - * Set charset - * - * @param string $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Set charset. */ - public function setCharset($pValue) + public function setCharset(int $pValue): self { - if ($pValue == '') { - $pValue = ''; - } $this->charset = $pValue; return $this; @@ -352,65 +344,61 @@ public function setItalic(bool $pValue = false): self } /** - * Get SuperScript. + * Set Baseline. */ - public function isSuperScript(): int + public function setBaseline(int $pValue): self { - return $this->superScript; + $this->baseline = $pValue; + + return $this; } /** - * Set SuperScript - * - * @param integer $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * Get Baseline. */ - public function setSuperScript($pValue = 0) + public function getBaseline(): int { - if ($pValue == '') { - $pValue = 0; - } - - $this->superScript = $pValue; - - // Set SubScript at false only if SuperScript is true - if ($pValue != 0) { - $this->subScript = 0; - } - - return $this; + return $this->baseline; } /** - * Get SubScript + * Get SuperScript. * - * @return integer + * @deprecated getBaseline() === self::BASELINE_SUPERSCRIPT */ - public function isSubScript() + public function isSuperScript(): bool { - return $this->subScript; + return $this->getBaseline() === self::BASELINE_SUPERSCRIPT; } /** - * Set SubScript + * Set SuperScript. * - * @param integer $pValue - * @return \PhpOffice\PhpPresentation\Style\Font + * @deprecated setBaseline(self::BASELINE_SUPERSCRIPT) */ - public function setSubScript($pValue = 0) + public function setSuperScript(bool $pValue = false): self { - if ($pValue == '') { - $pValue = 0; - } - - $this->subScript = $pValue; + return $this->setBaseline($pValue ? self::BASELINE_SUPERSCRIPT : ($this->getBaseline() == self::BASELINE_SUBSCRIPT ? $this->getBaseline() : 0)); + } - // Set SuperScript at false only if SubScript is true - if ($pValue != 0) { - $this->superScript = 0; - } + /** + * Get SubScript. + * + * @deprecated getBaseline() === self::BASELINE_SUBSCRIPT + */ + public function isSubScript(): bool + { + return $this->getBaseline() === self::BASELINE_SUBSCRIPT; + } - return $this; + /** + * Set SubScript. + * + * @deprecated setBaseline(self::BASELINE_SUBSCRIPT) + */ + public function setSubScript(bool $pValue = false): self + { + return $this->setBaseline($pValue ? self::BASELINE_SUBSCRIPT : ($this->getBaseline() == self::BASELINE_SUPERSCRIPT ? $this->getBaseline() : 0)); } /** @@ -463,21 +451,43 @@ public function setUnderline(string $pValue = self::UNDERLINE_NONE): self /** * Get Strikethrough. + * + * @deprecated Use `getStrikethrough` */ public function isStrikethrough(): bool + { + return $this->strikethrough !== self::STRIKE_NONE; + } + + /** + * Get Strikethrough. + */ + public function getStrikethrough(): string { return $this->strikethrough; } /** * Set Strikethrough. + * + * @deprecated $pValue as boolean + * + * @param bool|string $pValue + * + * @return self */ - public function setStrikethrough($pValue = self::STRIKE_NONE) + public function setStrikethrough($pValue = false) { - if ($pValue == '') { - $pValue = self::STRIKE_NONE; + if (is_bool($pValue)) { + $pValue = $pValue ? self::STRIKE_SINGLE : self::STRIKE_NONE; + } + if (in_array($pValue, [ + self::STRIKE_NONE, + self::STRIKE_SINGLE, + self::STRIKE_DOUBLE, + ])) { + $this->strikethrough = $pValue; } - $this->strikethrough = $pValue; return $this; } @@ -536,8 +546,7 @@ public function getHashCode(): string . $this->size . ($this->bold ? 't' : 'f') . ($this->italic ? 't' : 'f') - . ($this->superScript ? 't' : 'f') - . ($this->subScript ? 't' : 'f') + . $this->baseline . $this->underline . ($this->strikethrough ? 't' : 'f') . $this->format diff --git a/src/PhpPresentation/Style/Shadow.php b/src/PhpPresentation/Style/Shadow.php index bdbae7e04..af3b3e1c3 100644 --- a/src/PhpPresentation/Style/Shadow.php +++ b/src/PhpPresentation/Style/Shadow.php @@ -20,12 +20,17 @@ namespace PhpOffice\PhpPresentation\Style; use PhpOffice\PhpPresentation\ComparableInterface; +use PhpOffice\PhpPresentation\Exception\NotAllowedValueException; /** * \PhpOffice\PhpPresentation\Style\Shadow. */ class Shadow implements ComparableInterface { + public const TYPE_SHADOW_INNER = 'innerShdw'; + public const TYPE_SHADOW_OUTER = 'outerShdw'; + public const TYPE_REFLECTION = 'reflection'; + // Shadow alignment public const SHADOW_BOTTOM = 'b'; public const SHADOW_BOTTOM_LEFT = 'bl'; @@ -81,6 +86,11 @@ class Shadow implements ComparableInterface */ private $alpha = 50; + /** + * @var string + */ + private $type = self::TYPE_SHADOW_OUTER; + /** * Hash index. * @@ -224,6 +234,31 @@ public function setAlpha(int $pValue = 0): self return $this; } + /** + * Get Type. + */ + public function getType(): string + { + return $this->type; + } + + /** + * Set Type. + */ + public function setType(string $pValue = self::TYPE_SHADOW_OUTER): self + { + if (!in_array( + $pValue, + [self::TYPE_REFLECTION, self::TYPE_SHADOW_INNER, self::TYPE_SHADOW_OUTER] + )) { + throw new NotAllowedValueException($pValue, [self::TYPE_REFLECTION, self::TYPE_SHADOW_INNER, self::TYPE_SHADOW_OUTER]); + } + + $this->type = $pValue; + + return $this; + } + /** * Get hash code. * @@ -231,7 +266,7 @@ public function setAlpha(int $pValue = 0): self */ public function getHashCode(): string { - return md5(($this->visible ? 't' : 'f') . $this->blurRadius . $this->distance . $this->direction . $this->alignment . $this->color->getHashCode() . $this->alpha . __CLASS__); + return md5(($this->visible ? 't' : 'f') . $this->blurRadius . $this->distance . $this->direction . $this->alignment . $this->type . $this->color->getHashCode() . $this->alpha . __CLASS__); } /** diff --git a/src/PhpPresentation/Traits/ShapeCollection.php b/src/PhpPresentation/Traits/ShapeCollection.php new file mode 100644 index 000000000..6c7582cb1 --- /dev/null +++ b/src/PhpPresentation/Traits/ShapeCollection.php @@ -0,0 +1,96 @@ + + */ + protected $shapeCollection = []; + + /** + * Get collection of shapes. + * + * @return array + */ + public function getShapeCollection(): array + { + return $this->shapeCollection; + } + + /** + * Search into collection of shapes for a name or/and a type. + * + * @return array + */ + public function searchShapes(?string $name = null, ?string $type = null): array + { + $found = []; + foreach ($this->getShapeCollection() as $shape) { + if ($name && $shape->getName() !== $name) { + continue; + } + if ($type && get_class($shape) !== $type) { + continue; + } + + $found[] = $shape; + } + + return $found; + } + + /** + * Get collection of shapes. + * + * @param array $shapeCollection + */ + public function setShapeCollection(array $shapeCollection = []): self + { + $this->shapeCollection = $shapeCollection; + + return $this; + } + + /** + * @return static + */ + public function addShape(AbstractShape $shape) + { + $this->shapeCollection[] = $shape; + + return $this; + } + + /** + * @return static + */ + public function unsetShape(int $key) + { + unset($this->shapeCollection[$key]); + + return $this; + } +} diff --git a/src/PhpPresentation/Writer/AbstractDecoratorWriter.php b/src/PhpPresentation/Writer/AbstractDecoratorWriter.php index aab1d0eda..ddcce2a31 100644 --- a/src/PhpPresentation/Writer/AbstractDecoratorWriter.php +++ b/src/PhpPresentation/Writer/AbstractDecoratorWriter.php @@ -28,7 +28,7 @@ abstract class AbstractDecoratorWriter abstract public function render(): ZipInterface; /** - * @var \PhpOffice\PhpPresentation\HashTable + * @var HashTable */ protected $oHashTable; diff --git a/src/PhpPresentation/Writer/AbstractWriter.php b/src/PhpPresentation/Writer/AbstractWriter.php index 3d935c417..edbfb89c8 100644 --- a/src/PhpPresentation/Writer/AbstractWriter.php +++ b/src/PhpPresentation/Writer/AbstractWriter.php @@ -19,7 +19,6 @@ namespace PhpOffice\PhpPresentation\Writer; -use ArrayIterator; use PhpOffice\Common\Adapter\Zip\ZipInterface; use PhpOffice\PhpPresentation\AbstractShape; use PhpOffice\PhpPresentation\HashTable; @@ -116,7 +115,7 @@ protected function allDrawings(): array // Loop through PhpPresentation foreach (array_merge($this->getPhpPresentation()->getAllSlides(), $aSlideMasters, $aSlideLayouts) as $oSlide) { - $arrayReturn = $this->iterateCollection($oSlide->getShapeCollection()->getIterator()); + $arrayReturn = $this->iterateCollection($oSlide->getShapeCollection()); $aDrawings = array_merge($aDrawings, $arrayReturn); } @@ -124,28 +123,23 @@ protected function allDrawings(): array } /** - * @param ArrayIterator $oIterator + * @param array $collection * * @return array */ - private function iterateCollection(ArrayIterator $oIterator): array + private function iterateCollection(array $collection): array { $arrayReturn = []; - if ($oIterator->count() <= 0) { - return $arrayReturn; - } - while ($oIterator->valid()) { - $oShape = $oIterator->current(); + foreach ($collection as $oShape) { if ($oShape instanceof AbstractDrawingAdapter) { $arrayReturn[] = $oShape; } elseif ($oShape instanceof Chart) { $arrayReturn[] = $oShape; } elseif ($oShape instanceof Group) { - $arrayGroup = $this->iterateCollection($oShape->getShapeCollection()->getIterator()); + $arrayGroup = $this->iterateCollection($oShape->getShapeCollection()); $arrayReturn = array_merge($arrayReturn, $arrayGroup); } - $oIterator->next(); } return $arrayReturn; diff --git a/src/PhpPresentation/Writer/ODPresentation.php b/src/PhpPresentation/Writer/ODPresentation.php index 5c8432fac..f142fe06c 100644 --- a/src/PhpPresentation/Writer/ODPresentation.php +++ b/src/PhpPresentation/Writer/ODPresentation.php @@ -156,7 +156,7 @@ public function hasDiskCaching() * * @param string $directory Disk caching directory * - * @return \PhpOffice\PhpPresentation\Writer\ODPresentation + * @return ODPresentation */ public function setUseDiskCaching(bool $pValue = false, ?string $directory = null) { diff --git a/src/PhpPresentation/Writer/ODPresentation/Content.php b/src/PhpPresentation/Writer/ODPresentation/Content.php index c12a2fc11..33de96a40 100644 --- a/src/PhpPresentation/Writer/ODPresentation/Content.php +++ b/src/PhpPresentation/Writer/ODPresentation/Content.php @@ -27,7 +27,6 @@ use PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\Shape\Comment; use PhpOffice\PhpPresentation\Shape\Drawing\AbstractDrawingAdapter; -use PhpOffice\PhpPresentation\Shape\Drawing as ShapeDrawing; use PhpOffice\PhpPresentation\Shape\Group; use PhpOffice\PhpPresentation\Shape\Line; use PhpOffice\PhpPresentation\Shape\Media; @@ -448,10 +447,8 @@ protected function writeShapeMedia(XMLWriter $objWriter, Media $shape): void /** * Write picture. - * - * @param AbstractDrawingAdapter $shape */ - protected function writeShapeDrawing(XMLWriter $objWriter, ShapeDrawing\AbstractDrawingAdapter $shape): void + protected function writeShapeDrawing(XMLWriter $objWriter, AbstractDrawingAdapter $shape): void { // draw:frame $objWriter->startElement('draw:frame'); @@ -565,9 +562,9 @@ protected function writeShapeTxt(XMLWriter $objWriter, RichText $shape): void } } $objWriter->endElement(); - //=============================================== - // Bullet list - //=============================================== + //=============================================== + // Bullet list + //=============================================== } elseif ('bullet' == $paragraph->getBulletStyle()->getBulletType()) { $bCstShpHasBullet = true; // Open the bullet list diff --git a/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php b/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php index c58b25d60..e2f896c2a 100644 --- a/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php +++ b/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php @@ -311,7 +311,7 @@ protected function writeAxisStyle(Chart $chart): void $this->writeGridlineStyle($chart->getPlotArea()->getAxisY()->getMinorGridlines(), 'styleAxisYGridlinesMinor'); } - protected function writeAxisMainStyle(Chart\Axis $axis, string $styleName, AbstractType $chartType): void + protected function writeAxisMainStyle(Axis $axis, string $styleName, AbstractType $chartType): void { // style:style $this->xmlContent->startElement('style:style'); @@ -363,7 +363,7 @@ protected function writeAxisMainStyle(Chart\Axis $axis, string $styleName, Abstr $this->xmlContent->endElement(); } - protected function writeAxisTitleStyle(Chart\Axis $axis, string $styleName): void + protected function writeAxisTitleStyle(Axis $axis, string $styleName): void { // style:style $this->xmlContent->startElement('style:style'); diff --git a/src/PhpPresentation/Writer/PowerPoint2007.php b/src/PhpPresentation/Writer/PowerPoint2007.php index a116ca8a3..dd46c37ee 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007.php +++ b/src/PhpPresentation/Writer/PowerPoint2007.php @@ -147,7 +147,7 @@ public function hasDiskCaching() * * @param string $directory Disk caching directory * - * @return \PhpOffice\PhpPresentation\Writer\PowerPoint2007 + * @return PowerPoint2007 */ public function setUseDiskCaching(bool $useDiskCaching = false, ?string $directory = null) { diff --git a/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php b/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php index 79ea0c22a..58ef3b244 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/AbstractSlide.php @@ -49,6 +49,7 @@ use PhpOffice\PhpPresentation\Style\Border; use PhpOffice\PhpPresentation\Style\Bullet; use PhpOffice\PhpPresentation\Style\Color; +use PhpOffice\PhpPresentation\Style\Font; use PhpOffice\PhpPresentation\Style\Shadow; abstract class AbstractSlide extends AbstractDecoratorWriter @@ -58,60 +59,56 @@ abstract class AbstractSlide extends AbstractDecoratorWriter */ protected function writeDrawingRelations(AbstractSlideAlias $pSlideMaster, XMLWriter $objWriter, int $relId) { - if ($pSlideMaster->getShapeCollection()->count() > 0) { + if (count($pSlideMaster->getShapeCollection()) > 0) { // Loop trough images and write relationships - $iterator = $pSlideMaster->getShapeCollection()->getIterator(); - while ($iterator->valid()) { - if ($iterator->current() instanceof ShapeDrawingFile || $iterator->current() instanceof ShapeDrawingGd) { + foreach ($pSlideMaster->getShapeCollection() as $shape) { + if ($shape instanceof ShapeDrawingFile || $shape instanceof ShapeDrawingGd) { // Write relationship for image drawing $this->writeRelationship( $objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', - '../media/' . str_replace(' ', '_', $iterator->current()->getIndexedFilename()) + '../media/' . str_replace(' ', '_', $shape->getIndexedFilename()) ); - $iterator->current()->relationId = 'rId' . $relId; + $shape->relationId = 'rId' . $relId; ++$relId; - } elseif ($iterator->current() instanceof ShapeChart) { + } elseif ($shape instanceof ShapeChart) { // Write relationship for chart drawing $this->writeRelationship( $objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', - '../charts/' . $iterator->current()->getIndexedFilename() + '../charts/' . $shape->getIndexedFilename() ); - $iterator->current()->relationId = 'rId' . $relId; + $shape->relationId = 'rId' . $relId; ++$relId; - } elseif ($iterator->current() instanceof Group) { - $iterator2 = $iterator->current()->getShapeCollection()->getIterator(); - while ($iterator2->valid()) { - if ($iterator2->current() instanceof ShapeDrawingFile || - $iterator2->current() instanceof ShapeDrawingGd + } elseif ($shape instanceof Group) { + foreach ($shape->getShapeCollection() as $subShape) { + if ($subShape instanceof ShapeDrawingFile || + $subShape instanceof ShapeDrawingGd ) { // Write relationship for image drawing $this->writeRelationship( $objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', - '../media/' . str_replace(' ', '_', $iterator2->current()->getIndexedFilename()) + '../media/' . str_replace(' ', '_', $subShape->getIndexedFilename()) ); - $iterator2->current()->relationId = 'rId' . $relId; + $subShape->relationId = 'rId' . $relId; ++$relId; - } elseif ($iterator2->current() instanceof ShapeChart) { + } elseif ($subShape instanceof ShapeChart) { // Write relationship for chart drawing $this->writeRelationship( $objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart', - '../charts/' . $iterator2->current()->getIndexedFilename() + '../charts/' . $subShape->getIndexedFilename() ); - $iterator2->current()->relationId = 'rId' . $relId; + $subShape->relationId = 'rId' . $relId; ++$relId; } - $iterator2->next(); } } - $iterator->next(); } } @@ -228,7 +225,7 @@ protected function writeShapeText(XMLWriter $objWriter, RichText $shape, int $sh $this->writeFill($objWriter, $shape->getFill()); $this->writeBorder($objWriter, $shape->getBorder(), ''); - $this->writeEffect($objWriter, $shape->getEffectCollection()); + $this->writeShadow($objWriter, $shape->getShadow()); // > p:sp\p:spPr $objWriter->endElement(); @@ -238,10 +235,12 @@ protected function writeShapeText(XMLWriter $objWriter, RichText $shape, int $sh //@link :http://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.bodyproperties%28v=office.14%29.aspx $objWriter->startElement('a:bodyPr'); if (!$shape->isPlaceholder()) { + // Vertical alignment $verticalAlign = $shape->getActiveParagraph()->getAlignment()->getVertical(); if (Alignment::VERTICAL_BASE != $verticalAlign && Alignment::VERTICAL_AUTO != $verticalAlign) { $objWriter->writeAttribute('anchor', $verticalAlign); } + $objWriter->writeAttribute('anchorCtr', $shape->getVerticalAlignCenter()); if (RichText::WRAP_SQUARE != $shape->getWrap()) { $objWriter->writeAttribute('wrap', $shape->getWrap()); } @@ -255,20 +254,12 @@ protected function writeShapeText(XMLWriter $objWriter, RichText $shape, int $sh if ($shape->isUpright()) { $objWriter->writeAttribute('upright', '1'); } - if ($shape->isVertical()) { - $objWriter->writeAttribute('vert', 'vert'); - } - else { - $objWriter->writeAttribute('vert', 'horz'); - } + $objWriter->writeAttribute('vert', $shape->isVertical() ? 'vert' : 'horz'); $objWriter->writeAttribute('bIns', CommonDrawing::pixelsToEmu($shape->getInsetBottom())); $objWriter->writeAttribute('lIns', CommonDrawing::pixelsToEmu($shape->getInsetLeft())); $objWriter->writeAttribute('rIns', CommonDrawing::pixelsToEmu($shape->getInsetRight())); $objWriter->writeAttribute('tIns', CommonDrawing::pixelsToEmu($shape->getInsetTop())); - // Vertical alignment - $objWriter->writeAttribute('anchor', $shape->getVerticalAlignment()); - $objWriter->writeAttribute('anchorCtr', (int)$shape->getVerticalAlignCenter()); - if ($shape->getColumns() <> 1) { + if ($shape->getColumns() != 1) { $objWriter->writeAttribute('numCol', $shape->getColumns()); $objWriter->writeAttribute('spcCol', CommonDrawing::pixelsToEmu($shape->getColumnSpacing())); } @@ -571,7 +562,7 @@ protected function writeParagraphs(XMLWriter $objWriter, array $paragraphs): voi /** * Write Paragraph Styles (a:pPr). */ - protected function writeParagraphStyles(XMLWriter $objWriter, RichText\Paragraph $paragraph, bool $isPlaceholder = false): void + protected function writeParagraphStyles(XMLWriter $objWriter, Paragraph $paragraph, bool $isPlaceholder = false): void { $objWriter->startElement('a:pPr'); $objWriter->writeAttribute('algn', $paragraph->getAlignment()->getHorizontal()); @@ -645,7 +636,7 @@ protected function writeParagraphStyles(XMLWriter $objWriter, RichText\Paragraph /** * Write RichTextElement Styles (a:pPr). */ - protected function writeRunStyles(XMLWriter $objWriter, RichText\Run $element): void + protected function writeRunStyles(XMLWriter $objWriter, Run $element): void { // a:rPr $objWriter->startElement('a:rPr'); @@ -655,7 +646,9 @@ protected function writeRunStyles(XMLWriter $objWriter, RichText\Run $element): $objWriter->writeAttributeIf($element->getFont()->isBold(), 'b', '1'); $objWriter->writeAttributeIf($element->getFont()->isItalic(), 'i', '1'); - $objWriter->writeAttributeIf($element->getFont()->isStrikethrough(), 'strike', $element->getFont()->isStrikethrough()); + + // Strikethrough + $objWriter->writeAttribute('strike', $element->getFont()->getStrikethrough()); // Size $objWriter->writeAttribute('sz', ($element->getFont()->getSize() * 100)); @@ -669,30 +662,37 @@ protected function writeRunStyles(XMLWriter $objWriter, RichText\Run $element): // Capitalization $objWriter->writeAttribute('cap', $element->getFont()->getCapitalization()); - // Superscript / subscript - $objWriter->writeAttributeIf($element->getFont()->isSuperScript() != 0, 'baseline', (int)$element->getFont()->isSuperScript()); - $objWriter->writeAttributeIf($element->getFont()->isSubScript() != 0, 'baseline', (int)$element->getFont()->isSubScript()); + // Baseline + $objWriter->writeAttributeIf($element->getFont()->getBaseline() !== 0, 'baseline', $element->getFont()->getBaseline()); // Color - a:solidFill $objWriter->startElement('a:solidFill'); $this->writeColor($objWriter, $element->getFont()->getColor()); $objWriter->endElement(); - // Write Effects - $this->writeEffect($objWriter, $element->getEffectCollection(), 'srgbClr'); - // Font // - a:latin // - a:ea // - a:cs $objWriter->startElement('a:' . $element->getFont()->getFormat()); $objWriter->writeAttribute('typeface', $element->getFont()->getName()); - if ($element->getFont()->getPanose()!="") - $objWriter->writeAttribute('panose', $element->getFont()->getPanose()); - if ($element->getFont()->getPitchFamily()!="") - $objWriter->writeAttribute('pitchFamily', $element->getFont()->getPitchFamily()); - if ($element->getFont()->getCharset()!="") - $objWriter->writeAttribute('charset', $element->getFont()->getCharset()); + if ($element->getFont()->getPanose() !== '') { + $panose = array_map(function (string $value) { + return '0' . $value; + }, str_split($element->getFont()->getPanose())); + + $objWriter->writeAttribute('panose', implode('', $panose)); + } + $objWriter->writeAttributeIf( + $element->getFont()->getPitchFamily() !== 0, + 'pitchFamily', + $element->getFont()->getPitchFamily() + ); + $objWriter->writeAttributeIf( + $element->getFont()->getCharset() !== Font::CHARSET_DEFAULT, + 'charset', + dechex($element->getFont()->getCharset()) + ); $objWriter->endElement(); // a:hlinkClick @@ -806,7 +806,7 @@ protected function writeShadow(XMLWriter $objWriter, Shadow $oShadow): void $objWriter->startElement('a:effectLst'); // a:outerShdw - $objWriter->startElement('a:outerShdw'); + $objWriter->startElement('a:' . $oShadow->getType()); $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($oShadow->getBlurRadius())); $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($oShadow->getDistance())); $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $oShadow->getDirection())); @@ -821,55 +821,7 @@ protected function writeShadow(XMLWriter $objWriter, Shadow $oShadow): void } /** - * Write Effect - * @param XMLWriter $objWriter - * @param array \PhpOffice\PhpPresentation\Style\Effect[] - * @param Shadow $oShadow - */ - protected function writeEffect(XMLWriter $objWriter, ?array $aEffect, ?string $tagClr=null) - { - // NO Effect => return - if (!isset($aEffect) && !is_array($aEffect)) { - return; - } - if (!isset($tagClr)) { - $tagClr = 'prstClr'; - } - - // a:effectLst - $objWriter->startElement('a:effectLst'); - // Write each effect - foreach($aEffect as $effect) { - // a: - if ( $effect->getEffectType() == 'outerShdw' - || $effect->getEffectType() == 'innerShdw') { -// @TODO || $effect->getEffectType() == 'reflection') { - - $objWriter->startElement('a:'.$effect->getEffectType()); - $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($effect->getBlurRadius())); - $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($effect->getDistance())); - $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle($effect->getDirection())); - $objWriter->writeAttribute('algn', $effect->getAlignment()); - $objWriter->writeAttribute('rotWithShape', '0'); - - // a:prstClr - $objWriter->startElement('a:'.$tagClr); - $objWriter->writeAttribute('val', $effect->getColor()->getRGB()); - // a:alpha - $objWriter->startElement('a:alpha'); - $objWriter->writeAttribute('val', $effect->getAlpha() * 1000); - $objWriter->endElement(); - $objWriter->endElement(); - - $objWriter->endElement(); - } - } - - $objWriter->endElement(); - } - - /** - * Write hyperlink + * Write hyperlink. * * @param XMLWriter $objWriter XML Writer * @param AbstractShape|TextElement $shape @@ -1500,7 +1452,7 @@ protected function writeShapePic(XMLWriter $objWriter, AbstractGraphic $shape, i $this->writeFill($objWriter, $shape->getFill()); $this->writeBorder($objWriter, $shape->getBorder(), ''); - $this->writeEffect($objWriter, $shape->getEffectCollection()); + $this->writeShadow($objWriter, $shape->getShadow()); $objWriter->endElement(); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php b/src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php index 541e8c1d1..aa8ea2a9d 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/ContentTypes.php @@ -85,7 +85,7 @@ public function render(): ZipInterface for ($i = 0; $i < $slideCount; ++$i) { $oSlide = $this->oPresentation->getSlide($i); $this->writeOverrideContentType($objWriter, '/ppt/slides/slide' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml'); - if ($oSlide->getNote()->getShapeCollection()->count() > 0) { + if (count($oSlide->getNote()->getShapeCollection()) > 0) { $this->writeOverrideContentType($objWriter, '/ppt/notesSlides/notesSlide' . ($i + 1) . '.xml', 'application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml'); } foreach ($oSlide->getShapeCollection() as $oShape) { diff --git a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCore.php b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCore.php index 6df85cde0..d21f6863a 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCore.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsCore.php @@ -70,18 +70,17 @@ public function render(): ZipInterface // cp:keywords $objWriter->writeElement('cp:keywords', $this->oPresentation->getDocumentProperties()->getKeywords()); + // cp:category + $objWriter->writeElement('cp:category', $this->oPresentation->getDocumentProperties()->getCategory()); + // cp:revision $objWriter->writeElement('cp:revision', $this->oPresentation->getDocumentProperties()->getRevision()); // cp:contentStatus - $objWriter->writeElement('cp:contentStatus', $this->oPresentation->getDocumentProperties()->getStatus()); - - // cp:category - $objWriter->writeElement('cp:category', $this->oPresentation->getDocumentProperties()->getCategory()); - if ($this->oPresentation->getPresentationProperties()->isMarkedAsFinal()) { - // cp:contentStatus = Final $objWriter->writeElement('cp:contentStatus', 'Final'); + } else { + $objWriter->writeElement('cp:contentStatus', $this->oPresentation->getDocumentProperties()->getStatus()); } $objWriter->endElement(); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsThumbnail.php b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsThumbnail.php index 103309e5c..aac86bc75 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/DocPropsThumbnail.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/DocPropsThumbnail.php @@ -25,26 +25,9 @@ class DocPropsThumbnail extends AbstractDecoratorWriter { public function render(): ZipInterface { - $pathThumbnail = $this->getPresentation()->getPresentationProperties()->getThumbnailPath(); - $type = $this->getPresentation()->getPresentationProperties()->getThumbnailType(); - - // From local file - if ($pathThumbnail && $type == \PhpOffice\PhpPresentation\PresentationProperties::THUMBNAIL_FILE) { - $fileThumbnail = file_get_contents($pathThumbnail); - $gdImage = imagecreatefromstring($fileThumbnail); - if ($gdImage) { - ob_start(); - imagejpeg($gdImage); - $imageContents = ob_get_contents(); - ob_end_clean(); - imagedestroy($gdImage); - $this->getZip()->addFromString('docProps/thumbnail.jpeg', $imageContents); - } - } - - // From ZIP original file - if ($pathThumbnail && $type == \PhpOffice\PhpPresentation\PresentationProperties::THUMBNAIL_ZIP) { - $gdImage = imagecreatefromstring($this->getPresentation()->getPresentationProperties()->getThumbnail()); + $thumnbail = $this->getPresentation()->getPresentationProperties()->getThumbnail(); + if ($thumnbail) { + $gdImage = imagecreatefromstring($thumnbail); if ($gdImage) { ob_start(); imagejpeg($gdImage); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php b/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php index d2cd90410..f28fb74ad 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php @@ -447,11 +447,10 @@ protected function writeTitle(XMLWriter $objWriter, Title $subject): void $objWriter->writeAttribute('dirty', '0'); $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $subject->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $subject->getFont()->getUnderline()); - $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($subject->getFont()->getBaseline() !== 0, 'baseline', $subject->getFont()->getBaseline()); $objWriter->writeAttribute('cap', $subject->getFont()->getCapitalization()); // Font - a:solidFill @@ -550,7 +549,6 @@ protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart * Write Legend. * * @param XMLWriter $objWriter XML Writer - * @param Chart\Legend $subject */ protected function writeLegend(XMLWriter $objWriter, Legend $subject): void { @@ -609,11 +607,10 @@ protected function writeLegend(XMLWriter $objWriter, Legend $subject): void $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $subject->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $subject->getFont()->getUnderline()); - $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($subject->getFont()->getBaseline() !== 0, 'baseline', $subject->getFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -703,7 +700,6 @@ protected function writeLayout(XMLWriter $objWriter, $subject): void * Write Type Area. * * @param XMLWriter $objWriter XML Writer - * @param Chart\Type\Area $subject */ protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void { @@ -804,7 +800,6 @@ protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $incl * Write Type Bar. * * @param XMLWriter $objWriter XML Writer - * @param Chart\Type\Bar $subject */ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void { @@ -895,11 +890,10 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includ $objWriter->startElement('a:defRPr'); $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline()); // a:solidFill $objWriter->startElement('a:solidFill'); @@ -1018,7 +1012,6 @@ protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includ * Write Type Bar3D. * * @param XMLWriter $objWriter XML Writer - * @param Chart\Type\Bar3D $subject */ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void { @@ -1102,11 +1095,10 @@ protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $in $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -1311,11 +1303,10 @@ protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bo $objWriter->startElement('a:defRPr'); $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline()); // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill $objWriter->startElement('a:solidFill'); @@ -1454,11 +1445,10 @@ protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includ $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -1618,11 +1608,10 @@ protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $in $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -1771,11 +1760,10 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $incl $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -1947,11 +1935,10 @@ protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $in $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000'); + $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -2113,11 +2100,10 @@ protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $series->getFont()->getUnderline()); - $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -2392,11 +2378,10 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $ty $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($oAxis->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $oAxis->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100)); $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline()); - $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($oAxis->getFont()->getBaseline() !== 0, 'baseline', $oAxis->getFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); @@ -2496,11 +2481,10 @@ protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $ty $objWriter->startElement('a:defRPr'); $objWriter->writeAttribute('b', ($oAxis->getTickLabelFont()->isBold() ? 'true' : 'false')); $objWriter->writeAttribute('i', ($oAxis->getTickLabelFont()->isItalic() ? 'true' : 'false')); - $objWriter->writeAttribute('strike', ($oAxis->getTickLabelFont()->isStrikethrough() ? 'sngStrike' : 'noStrike')); + $objWriter->writeAttribute('strike', $oAxis->getFont()->getStrikethrough()); $objWriter->writeAttribute('sz', ($oAxis->getTickLabelFont()->getSize() * 100)); $objWriter->writeAttribute('u', $oAxis->getTickLabelFont()->getUnderline()); - $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->isSuperScript(), 'baseline', '300000'); - $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->isSubScript(), 'baseline', '-250000'); + $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->getBaseline() !== 0, 'baseline', $oAxis->getTickLabelFont()->getBaseline()); // Font - a:solidFill $objWriter->startElement('a:solidFill'); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptSlides.php b/src/PhpPresentation/Writer/PowerPoint2007/PptSlides.php index 00da6cbf8..de600cdf1 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptSlides.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptSlides.php @@ -49,7 +49,7 @@ public function render(): ZipInterface // Add note slide if ($oSlide->getNote() instanceof Note) { - if ($oSlide->getNote()->getShapeCollection()->count() > 0) { + if (count($oSlide->getNote()->getShapeCollection()) > 0) { $this->oZip->addFromString('ppt/notesSlides/notesSlide' . ($idx + 1) . '.xml', $this->writeNote($oSlide->getNote())); } } @@ -96,16 +96,14 @@ protected function writeSlideRelationships(Slide $pSlide): string ++$relId; // Write drawing relationships? - if ($pSlide->getShapeCollection()->count() > 0) { - $collections = [$pSlide->getShapeCollection()->getIterator()]; + if (count($pSlide->getShapeCollection()) > 0) { + $collections = [$pSlide->getShapeCollection()]; // Loop trough images and write relationships while (count($collections)) { - $iterator = array_shift($collections); - - while ($iterator->valid()) { - $currentShape = $iterator->current(); + $collection = array_shift($collections); + foreach ($collection as $currentShape) { if ($currentShape instanceof Media) { // Write relationship for image drawing $currentShape->relationId = 'rId' . $relId; @@ -124,10 +122,8 @@ protected function writeSlideRelationships(Slide $pSlide): string $currentShape->relationId = 'rId' . $relId; ++$relId; } elseif ($currentShape instanceof ShapeContainerInterface) { - $collections[] = $currentShape->getShapeCollection()->getIterator(); + $collections[] = $currentShape->getShapeCollection(); } - - $iterator->next(); } } } @@ -141,14 +137,13 @@ protected function writeSlideRelationships(Slide $pSlide): string } // Write hyperlink relationships? - if ($pSlide->getShapeCollection()->count() > 0) { + if (count($pSlide->getShapeCollection()) > 0) { // Loop trough hyperlinks and write relationships - $iterator = $pSlide->getShapeCollection()->getIterator(); - while ($iterator->valid()) { + foreach ($pSlide->getShapeCollection() as $shape) { // Hyperlink on shape - if ($iterator->current()->hasHyperlink()) { + if ($shape->hasHyperlink()) { // Write relationship for hyperlink - $hyperlink = $iterator->current()->getHyperlink(); + $hyperlink = $shape->getHyperlink(); $hyperlink->relationId = 'rId' . $relId; if (!$hyperlink->isInternal()) { @@ -161,8 +156,8 @@ protected function writeSlideRelationships(Slide $pSlide): string } // Hyperlink on rich text run - if ($iterator->current() instanceof RichText) { - foreach ($iterator->current()->getParagraphs() as $paragraph) { + if ($shape instanceof RichText) { + foreach ($shape->getParagraphs() as $paragraph) { foreach ($paragraph->getRichTextElements() as $element) { if ($element instanceof Run || $element instanceof TextElement) { if ($element->hasHyperlink()) { @@ -184,14 +179,14 @@ protected function writeSlideRelationships(Slide $pSlide): string } // Hyperlink in table - if ($iterator->current() instanceof ShapeTable) { + if ($shape instanceof ShapeTable) { // Rows - $countRows = count($iterator->current()->getRows()); + $countRows = count($shape->getRows()); for ($row = 0; $row < $countRows; ++$row) { // Cells in rows - $countCells = count($iterator->current()->getRow($row)->getCells()); + $countCells = count($shape->getRow($row)->getCells()); for ($cell = 0; $cell < $countCells; ++$cell) { - $currentCell = $iterator->current()->getRow($row)->getCell($cell); + $currentCell = $shape->getRow($row)->getCell($cell); // Paragraphs in cell foreach ($currentCell->getParagraphs() as $paragraph) { // RichText in paragraph @@ -218,13 +213,12 @@ protected function writeSlideRelationships(Slide $pSlide): string } } - if ($iterator->current() instanceof Group) { - $iterator2 = $pSlide->getShapeCollection()->getIterator(); - while ($iterator2->valid()) { + if ($shape instanceof Group) { + foreach ($shape->getShapeCollection() as $subShape) { // Hyperlink on shape - if ($iterator2->current()->hasHyperlink()) { + if ($subShape->hasHyperlink()) { // Write relationship for hyperlink - $hyperlink = $iterator2->current()->getHyperlink(); + $hyperlink = $subShape->getHyperlink(); $hyperlink->relationId = 'rId' . $relId; if (!$hyperlink->isInternal()) { @@ -237,8 +231,8 @@ protected function writeSlideRelationships(Slide $pSlide): string } // Hyperlink on rich text run - if ($iterator2->current() instanceof RichText) { - foreach ($iterator2->current()->getParagraphs() as $paragraph) { + if ($subShape instanceof RichText) { + foreach ($subShape->getParagraphs() as $paragraph) { foreach ($paragraph->getRichTextElements() as $element) { if ($element instanceof Run || $element instanceof TextElement) { if ($element->hasHyperlink()) { @@ -260,14 +254,14 @@ protected function writeSlideRelationships(Slide $pSlide): string } // Hyperlink in table - if ($iterator2->current() instanceof ShapeTable) { + if ($subShape instanceof ShapeTable) { // Rows - $countRows = count($iterator2->current()->getRows()); + $countRows = count($subShape->getRows()); for ($row = 0; $row < $countRows; ++$row) { // Cells in rows - $countCells = count($iterator2->current()->getRow($row)->getCells()); + $countCells = count($subShape->getRow($row)->getCells()); for ($cell = 0; $cell < $countCells; ++$cell) { - $currentCell = $iterator2->current()->getRow($row)->getCell($cell); + $currentCell = $subShape->getRow($row)->getCell($cell); // Paragraphs in cell foreach ($currentCell->getParagraphs() as $paragraph) { // RichText in paragraph @@ -293,39 +287,30 @@ protected function writeSlideRelationships(Slide $pSlide): string } } } - - $iterator2->next(); } } - - $iterator->next(); } } // Write comment relationships - if ($pSlide->getShapeCollection()->count() > 0) { + if (count($pSlide->getShapeCollection()) > 0) { $hasSlideComment = false; // Loop trough images and write relationships - $iterator = $pSlide->getShapeCollection()->getIterator(); - while ($iterator->valid()) { - if ($iterator->current() instanceof Comment) { + foreach ($pSlide->getShapeCollection() as $shape) { + if ($shape instanceof Comment) { $hasSlideComment = true; break; - } elseif ($iterator->current() instanceof Group) { - $iterator2 = $iterator->current()->getShapeCollection()->getIterator(); - while ($iterator2->valid()) { - if ($iterator2->current() instanceof Comment) { + } elseif ($shape instanceof Group) { + foreach ($shape->getShapeCollection() as $subShape) { + if ($subShape instanceof Comment) { $hasSlideComment = true; break 2; } - $iterator2->next(); } } - - $iterator->next(); } if ($hasSlideComment) { @@ -334,7 +319,7 @@ protected function writeSlideRelationships(Slide $pSlide): string } } - if ($pSlide->getNote()->getShapeCollection()->count() > 0) { + if (count($pSlide->getNote()->getShapeCollection()) > 0) { $this->writeRelationship($objWriter, $relId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide', '../notesSlides/notesSlide' . ($idxSlide + 1) . '.xml'); } @@ -386,7 +371,7 @@ protected function writeSlide(Slide $pSlide): string $objWriter->endElement(); } - if ($oBackground instanceof Slide\Background\Image) { + if ($oBackground instanceof Image) { // a:blipFill $objWriter->startElement('a:blipFill'); diff --git a/src/PhpPresentation/Writer/PowerPoint2007/Relationships.php b/src/PhpPresentation/Writer/PowerPoint2007/Relationships.php index 804c175e2..7d652778c 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/Relationships.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/Relationships.php @@ -63,29 +63,18 @@ protected function writeRelationships(): string $this->writeRelationship($objWriter, 4, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties', 'docProps/custom.xml'); $idxRelation = 5; - // Thumbnail - $path = $this->getPresentation()->getPresentationProperties()->getThumbnailPath(); - $type = $this->getPresentation()->getPresentationProperties()->getThumbnailType(); - // From local file - if ($path && $type == \PhpOffice\PhpPresentation\PresentationProperties::THUMBNAIL_FILE) { - $pathThumbnail = file_get_contents($path); - $gdImage = imagecreatefromstring($pathThumbnail); - if ($gdImage) { - imagedestroy($gdImage); - // Relationship docProps/thumbnail.jpeg - $this->writeRelationship($objWriter, $idxRelation, 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail', 'docProps/thumbnail.jpeg'); - } - } - // From ZIP original file - if ($path && $type == \PhpOffice\PhpPresentation\PresentationProperties::THUMBNAIL_ZIP) { - $gdImage = imagecreatefromstring($this->getPresentation()->getPresentationProperties()->getThumbnail()); + + // Relationship docProps/thumbnail.jpeg + $thumnbail = $this->getPresentation()->getPresentationProperties()->getThumbnail(); + if ($thumnbail) { + $gdImage = imagecreatefromstring($thumnbail); if ($gdImage) { imagedestroy($gdImage); // Relationship docProps/thumbnail.jpeg $this->writeRelationship($objWriter, $idxRelation, 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail', 'docProps/thumbnail.jpeg'); + // $idxRelation++; } } - // ++$idxRelation $objWriter->endElement(); diff --git a/src/PhpPresentation/Writer/Serialized.php b/src/PhpPresentation/Writer/Serialized.php index 72ac2790a..34acb7d2e 100644 --- a/src/PhpPresentation/Writer/Serialized.php +++ b/src/PhpPresentation/Writer/Serialized.php @@ -66,12 +66,11 @@ public function save(string $pFilename): void // Add media $slideCount = $oPresentation->getSlideCount(); for ($i = 0; $i < $slideCount; ++$i) { - for ($j = 0; $j < $oPresentation->getSlide($i)->getShapeCollection()->count(); ++$j) { - if ($oPresentation->getSlide($i)->getShapeCollection()->offsetGet($j) instanceof AbstractDrawingAdapter) { - $imgTemp = $oPresentation->getSlide($i)->getShapeCollection()->offsetGet($j); + foreach ($oPresentation->getSlide($i)->getShapeCollection() as $shape) { + if ($shape instanceof AbstractDrawingAdapter) { $objZip->addFromString( - 'media/' . $imgTemp->getImageIndex() . '/' . pathinfo($imgTemp->getPath(), PATHINFO_BASENAME), - file_get_contents($imgTemp->getPath()) + 'media/' . $shape->getImageIndex() . '/' . pathinfo($shape->getPath(), PATHINFO_BASENAME), + file_get_contents($shape->getPath()) ); } } @@ -99,14 +98,13 @@ protected function writeSerialized(?PhpPresentation $pPhpPresentation = null, $p // Update media links $slideCount = $pPhpPresentation->getSlideCount(); for ($i = 0; $i < $slideCount; ++$i) { - for ($j = 0; $j < $pPhpPresentation->getSlide($i)->getShapeCollection()->count(); ++$j) { - if ($pPhpPresentation->getSlide($i)->getShapeCollection()->offsetGet($j) instanceof AbstractDrawingAdapter) { - $imgTemp = $pPhpPresentation->getSlide($i)->getShapeCollection()->offsetGet($j); - $imgPath = 'zip://' . $pFilename . '#media/' . $imgTemp->getImageIndex() . '/' . pathinfo($imgTemp->getPath(), PATHINFO_BASENAME); - if ($imgTemp instanceof File) { - $imgTemp->setPath($imgPath, false); + foreach ($pPhpPresentation->getSlide($i)->getShapeCollection() as $shape) { + if ($shape instanceof AbstractDrawingAdapter) { + $imgPath = 'zip://' . $pFilename . '#media/' . $shape->getImageIndex() . '/' . pathinfo($shape->getPath(), PATHINFO_BASENAME); + if ($shape instanceof File) { + $shape->setPath($imgPath, false); } else { - $imgTemp->setPath($imgPath); + $shape->setPath($imgPath); } } } diff --git a/tests/PhpPresentation/Tests/DocumentPropertiesTest.php b/tests/PhpPresentation/Tests/DocumentPropertiesTest.php index 5d0b37259..dd2a4d922 100644 --- a/tests/PhpPresentation/Tests/DocumentPropertiesTest.php +++ b/tests/PhpPresentation/Tests/DocumentPropertiesTest.php @@ -46,6 +46,8 @@ public function testGetSet(): void 'keywords' => '', 'category' => '', 'company' => '', + 'revision' => '', + 'status' => '', ]; foreach ($properties as $key => $val) { diff --git a/tests/PhpPresentation/Tests/PresentationPropertiesTest.php b/tests/PhpPresentation/Tests/PresentationPropertiesTest.php index db361430e..88b0920d7 100644 --- a/tests/PhpPresentation/Tests/PresentationPropertiesTest.php +++ b/tests/PhpPresentation/Tests/PresentationPropertiesTest.php @@ -130,14 +130,36 @@ public function testThumbnail(): void $object = new PresentationProperties(); self::assertNull($object->getThumbnailPath()); - self::assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath('AAAA')); + self::assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath('AAAA', PresentationProperties::THUMBNAIL_FILE)); self::assertNull($object->getThumbnailPath()); self::assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath()); self::assertNull($object->getThumbnailPath()); - self::assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath($imagePath)); + self::assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath($imagePath, PresentationProperties::THUMBNAIL_FILE)); self::assertEquals($imagePath, $object->getThumbnailPath()); + self::assertIsString($object->getThumbnail()); self::assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath()); self::assertEquals($imagePath, $object->getThumbnailPath()); + self::assertIsString($object->getThumbnail()); + } + + public function testThumbnailFileNotExisting(): void + { + $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'NotExistingFile.png'; + + $object = new PresentationProperties(); + self::assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath($imagePath, PresentationProperties::THUMBNAIL_FILE)); + self::assertNull($object->getThumbnailPath()); + self::assertNull($object->getThumbnail()); + } + + public function testThumbnailFileData(): void + { + $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'; + + $object = new PresentationProperties(); + self::assertInstanceOf(PresentationProperties::class, $object->setThumbnailPath($imagePath, PresentationProperties::THUMBNAIL_DATA, file_get_contents($imagePath))); + self::assertEquals('', $object->getThumbnailPath()); + self::assertIsString($object->getThumbnail()); } public function testZoom(): void diff --git a/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php b/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php index 8d04038ef..51b6ac3bf 100644 --- a/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php +++ b/tests/PhpPresentation/Tests/Reader/PowerPoint2007Test.php @@ -101,6 +101,8 @@ public function testLoadFile01(): void self::assertEquals('Sample 02 Description', $oPhpPresentation->getDocumentProperties()->getDescription()); self::assertEquals('office 2007 openxml libreoffice odt php', $oPhpPresentation->getDocumentProperties()->getKeywords()); self::assertEquals('Sample Category', $oPhpPresentation->getDocumentProperties()->getCategory()); + self::assertEquals('', $oPhpPresentation->getDocumentProperties()->getRevision()); + self::assertEquals('', $oPhpPresentation->getDocumentProperties()->getStatus()); self::assertIsArray($oPhpPresentation->getDocumentProperties()->getCustomProperties()); self::assertCount(0, $oPhpPresentation->getDocumentProperties()->getCustomProperties()); diff --git a/tests/PhpPresentation/Tests/Shape/GroupTest.php b/tests/PhpPresentation/Tests/Shape/GroupTest.php index 93cbbf7d7..f5b0eefc5 100644 --- a/tests/PhpPresentation/Tests/Shape/GroupTest.php +++ b/tests/PhpPresentation/Tests/Shape/GroupTest.php @@ -38,7 +38,7 @@ public function testConstruct(): void self::assertEquals(0, $object->getOffsetY()); self::assertEquals(0, $object->getExtentX()); self::assertEquals(0, $object->getExtentY()); - self::assertEquals(0, $object->getShapeCollection()->count()); + self::assertCount(0, $object->getShapeCollection()); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Group', $object->setWidth(mt_rand(1, 100))); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Group', $object->setHeight(mt_rand(1, 100))); } @@ -52,7 +52,7 @@ public function testAdd(): void self::assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Line', $object->createLineShape(10, 10, 10, 10)); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->createRichTextShape()); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Table', $object->createTableShape()); - self::assertEquals(5, $object->getShapeCollection()->count()); + self::assertCount(5, $object->getShapeCollection()); } public function testExtentX(): void diff --git a/tests/PhpPresentation/Tests/Shape/RichTextTest.php b/tests/PhpPresentation/Tests/Shape/RichTextTest.php index 4fd697574..e75137a1e 100644 --- a/tests/PhpPresentation/Tests/Shape/RichTextTest.php +++ b/tests/PhpPresentation/Tests/Shape/RichTextTest.php @@ -277,7 +277,7 @@ public function testHashCode(): void $object = new RichText(); $hash = $object->getActiveParagraph()->getHashCode(); - $hash .= RichText::WRAP_SQUARE . RichText::AUTOFIT_DEFAULT . RichText::OVERFLOW_OVERFLOW . RichText::OVERFLOW_OVERFLOW . '00104.89.69.64.8'; + $hash .= RichText::WRAP_SQUARE . RichText::AUTOFIT_DEFAULT . RichText::OVERFLOW_OVERFLOW . RichText::OVERFLOW_OVERFLOW . '00104.89.69.64.80'; $hash .= md5('00000' . $object->getFill()->getHashCode() . $object->getShadow()->getHashCode() . '' . get_parent_class($object)); $hash .= get_class($object); self::assertEquals(md5($hash), $object->getHashCode()); diff --git a/tests/PhpPresentation/Tests/Slide/AbstractSlideTest.php b/tests/PhpPresentation/Tests/Slide/AbstractSlideTest.php index d8d67a56f..bb93cc756 100644 --- a/tests/PhpPresentation/Tests/Slide/AbstractSlideTest.php +++ b/tests/PhpPresentation/Tests/Slide/AbstractSlideTest.php @@ -19,7 +19,9 @@ namespace PhpOffice\PhpPresentation\Tests\Slide; +use PhpOffice\PhpPresentation\Shape\Chart; use PhpOffice\PhpPresentation\Shape\RichText; +use PhpOffice\PhpPresentation\Shape\Table; use PhpOffice\PhpPresentation\Slide\AbstractSlide; use PHPUnit\Framework\TestCase; @@ -49,4 +51,36 @@ public function testCollection(): void self::assertIsArray($stub->getShapeCollection()); self::assertCount(count($array), $stub->getShapeCollection()); } + + public function testsearchShapes(): void + { + /** @var AbstractSlide $stub */ + $stub = $this->getMockForAbstractClass('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide'); + + $array = [ + (new RichText())->setName('AAA'), + (new Table())->setName('BBB'), + (new Chart())->setName('AAA'), + ]; + self::assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide', $stub->setShapeCollection($array)); + + // Search by Name + $result = $stub->searchShapes('AAA', null); + self::assertIsArray($result); + self::assertCount(2, $result); + self::assertInstanceOf(RichText::class, $result[0]); + self::assertInstanceOf(Chart::class, $result[1]); + + // Search by Name && Type + $result = $stub->searchShapes('AAA', Chart::class); + self::assertIsArray($result); + self::assertCount(1, $result); + self::assertInstanceOf(Chart::class, $result[0]); + + // Search by Type + $result = $stub->searchShapes(null, Table::class); + self::assertIsArray($result); + self::assertCount(1, $result); + self::assertInstanceOf(Table::class, $result[0]); + } } diff --git a/tests/PhpPresentation/Tests/Slide/NoteTest.php b/tests/PhpPresentation/Tests/Slide/NoteTest.php index 5cf4ce020..145b864a0 100644 --- a/tests/PhpPresentation/Tests/Slide/NoteTest.php +++ b/tests/PhpPresentation/Tests/Slide/NoteTest.php @@ -69,13 +69,13 @@ public function testOffset(): void public function testShape(): void { $object = new Note(); - self::assertEquals(0, $object->getShapeCollection()->count()); + self::assertCount(0, $object->getShapeCollection()); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->createRichTextShape()); - self::assertEquals(1, $object->getShapeCollection()->count()); + self::assertCount(1, $object->getShapeCollection()); $oRichText = new RichText(); - self::assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\RichText', $object->addShape($oRichText)); - self::assertEquals(2, $object->getShapeCollection()->count()); + self::assertInstanceOf(Note::class, $object->addShape($oRichText)); + self::assertCount(2, $object->getShapeCollection()); } /** diff --git a/tests/PhpPresentation/Tests/Slide/SlideLayoutTest.php b/tests/PhpPresentation/Tests/Slide/SlideLayoutTest.php index b3d23a42d..daea51b22 100644 --- a/tests/PhpPresentation/Tests/Slide/SlideLayoutTest.php +++ b/tests/PhpPresentation/Tests/Slide/SlideLayoutTest.php @@ -37,7 +37,7 @@ public function testBase(): void $object = new SlideLayout($mockSlideMaster); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide', $object); - self::assertInstanceOf('\\ArrayObject', $object->getShapeCollection()); + self::assertIsArray($object->getShapeCollection()); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\ColorMap', $object->colorMap); } diff --git a/tests/PhpPresentation/Tests/Slide/SlideMasterTest.php b/tests/PhpPresentation/Tests/Slide/SlideMasterTest.php index e910ae79a..b79cc1c31 100644 --- a/tests/PhpPresentation/Tests/Slide/SlideMasterTest.php +++ b/tests/PhpPresentation/Tests/Slide/SlideMasterTest.php @@ -38,7 +38,7 @@ public function testBase(): void $object = new SlideMaster(); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Slide\\AbstractSlide', $object); self::assertNull($object->getParent()); - self::assertInstanceOf('\\ArrayObject', $object->getShapeCollection()); + self::assertIsArray($object->getShapeCollection()); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\ColorMap', $object->colorMap); /** @var Color $background */ $background = $object->getBackground(); diff --git a/tests/PhpPresentation/Tests/Style/BorderTest.php b/tests/PhpPresentation/Tests/Style/BorderTest.php index 80b4d3498..279f0b345 100644 --- a/tests/PhpPresentation/Tests/Style/BorderTest.php +++ b/tests/PhpPresentation/Tests/Style/BorderTest.php @@ -51,7 +51,7 @@ public function testSetGetColor(): void $object = new Border(); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setColor()); self::assertNull($object->getColor()); - self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setColor(new Color(COLOR::COLOR_BLUE))); + self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setColor(new Color(Color::COLOR_BLUE))); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getColor()); self::assertEquals('FF0000FF', $object->getColor()->getARGB()); } @@ -66,7 +66,7 @@ public function testSetGetDashStyle(): void self::assertEquals(Border::DASH_SOLID, $object->getDashStyle()); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setDashStyle('')); self::assertEquals(Border::DASH_SOLID, $object->getDashStyle()); - self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setDashStyle(BORDER::DASH_DASH)); + self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setDashStyle(Border::DASH_DASH)); self::assertEquals(Border::DASH_DASH, $object->getDashStyle()); } @@ -91,7 +91,7 @@ public function testSetGetLineStyle(): void self::assertEquals(Border::LINE_SINGLE, $object->getLineStyle()); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setLineStyle('')); self::assertEquals(Border::LINE_SINGLE, $object->getLineStyle()); - self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setLineStyle(BORDER::LINE_DOUBLE)); + self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Border', $object->setLineStyle(Border::LINE_DOUBLE)); self::assertEquals(Border::LINE_DOUBLE, $object->getLineStyle()); } diff --git a/tests/PhpPresentation/Tests/Style/ColorTest.php b/tests/PhpPresentation/Tests/Style/ColorTest.php index 97485b57d..c4b5055f5 100644 --- a/tests/PhpPresentation/Tests/Style/ColorTest.php +++ b/tests/PhpPresentation/Tests/Style/ColorTest.php @@ -36,7 +36,7 @@ public function testConstruct(): void { $object = new Color(); self::assertEquals(Color::COLOR_BLACK, $object->getARGB()); - $object = new Color(COLOR::COLOR_BLUE); + $object = new Color(Color::COLOR_BLUE); self::assertEquals(Color::COLOR_BLUE, $object->getARGB()); } diff --git a/tests/PhpPresentation/Tests/Style/FillTest.php b/tests/PhpPresentation/Tests/Style/FillTest.php index 3430b430e..676156ed3 100644 --- a/tests/PhpPresentation/Tests/Style/FillTest.php +++ b/tests/PhpPresentation/Tests/Style/FillTest.php @@ -50,9 +50,9 @@ public function testConstruct(): void public function testSetGetEndColor(): void { $object = new Fill(); - self::assertInstanceOf(Fill::class, $object->setEndColor(new Color(COLOR::COLOR_BLUE))); + self::assertInstanceOf(Fill::class, $object->setEndColor(new Color(Color::COLOR_BLUE))); self::assertInstanceOf(Color::class, $object->getEndColor()); - self::assertEquals(COLOR::COLOR_BLUE, $object->getEndColor()->getARGB()); + self::assertEquals(Color::COLOR_BLUE, $object->getEndColor()->getARGB()); } /** @@ -86,9 +86,9 @@ public function testSetGetRotation(): void public function testSetGetStartColor(): void { $object = new Fill(); - self::assertInstanceOf(Fill::class, $object->setStartColor(new Color(COLOR::COLOR_BLUE))); + self::assertInstanceOf(Fill::class, $object->setStartColor(new Color(Color::COLOR_BLUE))); self::assertInstanceOf(Color::class, $object->getStartColor()); - self::assertEquals(COLOR::COLOR_BLUE, $object->getStartColor()->getARGB()); + self::assertEquals(Color::COLOR_BLUE, $object->getStartColor()->getARGB()); } /** diff --git a/tests/PhpPresentation/Tests/Style/FontTest.php b/tests/PhpPresentation/Tests/Style/FontTest.php index 711c2da53..6eabdd74b 100644 --- a/tests/PhpPresentation/Tests/Style/FontTest.php +++ b/tests/PhpPresentation/Tests/Style/FontTest.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpPresentation\Tests\Style; +use PhpOffice\PhpPresentation\Exception\InvalidParameterException; use PhpOffice\PhpPresentation\Exception\NotAllowedValueException; use PhpOffice\PhpPresentation\Style\Color; use PhpOffice\PhpPresentation\Style\Font; @@ -49,6 +50,18 @@ public function testConstruct(): void self::assertEquals(Font::CAPITALIZATION_NONE, $object->getCapitalization()); self::assertInstanceOf('PhpOffice\\PhpPresentation\\Style\\Color', $object->getColor()); self::assertEquals(Color::COLOR_BLACK, $object->getColor()->getARGB()); + self::assertEquals(0, $object->getBaseline()); + } + + /** + * Test get/set Baseline. + */ + public function testBaseline(): void + { + $object = new Font(); + self::assertEquals(0, $object->getBaseline()); + self::assertInstanceOf(Font::class, $object->setBaseline(Font::BASELINE_SUBSCRIPT)); + self::assertEquals(Font::BASELINE_SUBSCRIPT, $object->getBaseline()); } /** @@ -76,6 +89,17 @@ public function testCapitalizationException(): void $object->setCapitalization('Invalid'); } + /** + * Test get/set charset. + */ + public function testCharset(): void + { + $object = new Font(); + self::assertEquals(Font::CHARSET_DEFAULT, $object->getCharset()); + self::assertInstanceOf(Font::class, $object->setCharset(12)); + self::assertEquals(12, $object->getCharset()); + } + /** * Test get/set Character Spacing. */ @@ -134,6 +158,52 @@ public function testName(): void self::assertEquals('Arial', $object->getName()); } + /** + * Test get/set panose. + */ + public function testPanose(): void + { + $object = new Font(); + self::assertEquals('', $object->getPanose()); + self::assertInstanceOf(Font::class, $object->setPanose('4494D72242')); + self::assertEquals('4494D72242', $object->getPanose()); + } + + /** + * Test get/set panose (Exception : Invalid Length). + */ + public function testPanoseExceptionInvalidLength(): void + { + $this->expectException(InvalidParameterException::class); + $this->expectExceptionMessage('The parameter pValue can\'t have the value "12345" (Validation: The length is not equals to 10)'); + + $object = new Font(); + $object->setPanose('12345'); + } + + /** + * Test get/set panose (Exception : Invalid Char). + */ + public function testPanoseExceptionInvalidChar(): void + { + $this->expectException(InvalidParameterException::class); + $this->expectExceptionMessage('The parameter pValue can\'t have the value "4494D7224X" (Validation: The character "X" is not allowed)'); + + $object = new Font(); + $object->setPanose('4494D7224X'); + } + + /** + * Test get/set pitch family. + */ + public function testPitchFamily(): void + { + $object = new Font(); + self::assertEquals(0, $object->getPitchFamily()); + self::assertInstanceOf(Font::class, $object->setPitchFamily(12)); + self::assertEquals(12, $object->getPitchFamily()); + } + /** * Test get/set size. */ @@ -154,11 +224,11 @@ public function testUnderline(): void { $object = new Font(); self::assertInstanceOf(Font::class, $object->setUnderline()); - self::assertEquals(FONT::UNDERLINE_NONE, $object->getUnderline()); + self::assertEquals(Font::UNDERLINE_NONE, $object->getUnderline()); self::assertInstanceOf(Font::class, $object->setUnderline('')); - self::assertEquals(FONT::UNDERLINE_NONE, $object->getUnderline()); - self::assertInstanceOf(Font::class, $object->setUnderline(FONT::UNDERLINE_DASH)); - self::assertEquals(FONT::UNDERLINE_DASH, $object->getUnderline()); + self::assertEquals(Font::UNDERLINE_NONE, $object->getUnderline()); + self::assertInstanceOf(Font::class, $object->setUnderline(Font::UNDERLINE_DASH)); + self::assertEquals(Font::UNDERLINE_DASH, $object->getUnderline()); } /** @@ -197,10 +267,18 @@ public function testSetIsStriketrough(): void $object = new Font(); self::assertInstanceOf(Font::class, $object->setStrikethrough()); self::assertFalse($object->isStrikethrough()); + self::assertEquals(Font::STRIKE_NONE, $object->getStrikethrough()); + // boolean self::assertInstanceOf(Font::class, $object->setStrikethrough(false)); self::assertFalse($object->isStrikethrough()); + self::assertEquals(Font::STRIKE_NONE, $object->getStrikethrough()); self::assertInstanceOf(Font::class, $object->setStrikethrough(true)); self::assertTrue($object->isStrikethrough()); + self::assertEquals(Font::STRIKE_SINGLE, $object->getStrikethrough()); + // string + self::assertInstanceOf(Font::class, $object->setStrikethrough(Font::STRIKE_DOUBLE)); + self::assertTrue($object->isStrikethrough()); + self::assertEquals(Font::STRIKE_DOUBLE, $object->getStrikethrough()); } /** diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCoreTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCoreTest.php index 3a87a2613..5c79a1ee8 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCoreTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsCoreTest.php @@ -25,13 +25,6 @@ class DocPropsCoreTest extends PhpPresentationTestCase { protected $writerName = 'PowerPoint2007'; - public function testRender(): void - { - $this->assertZipFileExists('docProps/core.xml'); - $this->assertZipXmlElementNotExists('docProps/core.xml', '/cp:coreProperties/cp:contentStatus'); - $this->assertIsSchemaECMA376Valid(); - } - public function testDocumentProperties(): void { $expected = 'aAbBcDeE'; @@ -42,7 +35,9 @@ public function testDocumentProperties(): void ->setDescription($expected) ->setSubject($expected) ->setKeywords($expected) - ->setCategory($expected); + ->setCategory($expected) + ->setRevision($expected) + ->setStatus($expected); $this->assertZipFileExists('docProps/core.xml'); $this->assertZipXmlElementExists('docProps/core.xml', '/cp:coreProperties/dc:creator'); @@ -57,6 +52,10 @@ public function testDocumentProperties(): void $this->assertZipXmlElementEquals('docProps/core.xml', '/cp:coreProperties/cp:keywords', $expected); $this->assertZipXmlElementExists('docProps/core.xml', '/cp:coreProperties/cp:category'); $this->assertZipXmlElementEquals('docProps/core.xml', '/cp:coreProperties/cp:category', $expected); + $this->assertZipXmlElementExists('docProps/core.xml', '/cp:coreProperties/cp:revision'); + $this->assertZipXmlElementEquals('docProps/core.xml', '/cp:coreProperties/cp:revision', $expected); + $this->assertZipXmlElementExists('docProps/core.xml', '/cp:coreProperties/cp:contentStatus'); + $this->assertZipXmlElementEquals('docProps/core.xml', '/cp:coreProperties/cp:contentStatus', $expected); $this->assertIsSchemaECMA376Valid(); } @@ -73,7 +72,8 @@ public function testMarkAsFinalFalse(): void { $this->oPresentation->getPresentationProperties()->markAsFinal(false); - $this->assertZipXmlElementNotExists('docProps/core.xml', '/cp:coreProperties/cp:contentStatus'); + $this->assertZipXmlElementExists('docProps/core.xml', '/cp:coreProperties/cp:contentStatus'); + $this->assertZipXmlElementEquals('docProps/core.xml', '/cp:coreProperties/cp:contentStatus', ''); $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsThumbnailTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsThumbnailTest.php index cd29a9733..ddab8a1cc 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsThumbnailTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/DocPropsThumbnailTest.php @@ -19,6 +19,7 @@ namespace PhpPresentation\Tests\Writer\PowerPoint2007; +use PhpOffice\PhpPresentation\PresentationProperties; use PhpOffice\PhpPresentation\Tests\PhpPresentationTestCase; /** @@ -31,15 +32,40 @@ class DocPropsThumbnailTest extends PhpPresentationTestCase public function testRender(): void { $this->assertZipFileNotExists('docProps/thumbnail.jpeg'); + $this->assertZipXmlElementNotExists('_rels/.rels', '/Relationships/Relationship[@Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"]'); $this->assertIsSchemaECMA376Valid(); } - public function testFeatureThumbnail(): void + public function testFeatureThumbnailFile(): void { $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'; - $this->oPresentation->getPresentationProperties()->setThumbnailPath($imagePath); + $this->oPresentation->getPresentationProperties() + ->setThumbnailPath($imagePath, PresentationProperties::THUMBNAIL_FILE); $this->assertZipFileExists('docProps/thumbnail.jpeg'); + $this->assertZipXmlElementExists('_rels/.rels', '/Relationships/Relationship[@Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"]'); + $this->assertIsSchemaECMA376Valid(); + } + + public function testFeatureThumbnailFileNotExisting(): void + { + $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'NotExistingFile.png'; + + $this->oPresentation->getPresentationProperties() + ->setThumbnailPath($imagePath, PresentationProperties::THUMBNAIL_FILE); + $this->assertZipFileNotExists('docProps/thumbnail.jpeg'); + $this->assertZipXmlElementNotExists('_rels/.rels', '/Relationships/Relationship[@Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"]'); + $this->assertIsSchemaECMA376Valid(); + } + + public function testFeatureThumbnailData(): void + { + $imagePath = PHPPRESENTATION_TESTS_BASE_DIR . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'PhpPresentationLogo.png'; + + $this->oPresentation->getPresentationProperties() + ->setThumbnailPath('', PresentationProperties::THUMBNAIL_DATA, file_get_contents($imagePath)); + $this->assertZipFileExists('docProps/thumbnail.jpeg'); + $this->assertZipXmlElementExists('_rels/.rels', '/Relationships/Relationship[@Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail"]'); $this->assertIsSchemaECMA376Valid(); } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlideMastersTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlideMastersTest.php index c4374b6d1..67181ac06 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlideMastersTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlideMastersTest.php @@ -62,7 +62,7 @@ public function testWriteSlideMasterRelationships(): void ->willReturn($layouts); /** @var ArrayObject $collection */ - $collection = new ArrayObject(); + $collection = []; $collection[] = new ShapeDrawingFile(); $collection[] = new ShapeDrawingFile(); $collection[] = new ShapeDrawingFile(); diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlidesTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlidesTest.php index 9e0640477..652ebd5b4 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlidesTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptSlidesTest.php @@ -868,6 +868,53 @@ public function testRichTextHyperlink(): void $this->assertIsSchemaECMA376Valid(); } + public function testRichTextRunFontCharset(): void + { + $latinElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:latin'; + $eastAsianElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:ea'; + $complexScriptElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:cs'; + + $oSlide = $this->oPresentation->getActiveSlide(); + $oRichText = $oSlide->createRichTextShape(); + $oRun = $oRichText->createTextRun('MyText'); + $oRun->getFont()->setCharset(18); + + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $latinElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $latinElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $latinElement, 'charset'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $latinElement, 'charset', '12'); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertIsSchemaECMA376Valid(); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $eastAsianElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $eastAsianElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $eastAsianElement, 'charset'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $eastAsianElement, 'charset', '12'); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertIsSchemaECMA376Valid(); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $complexScriptElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $complexScriptElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $complexScriptElement, 'charset'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $complexScriptElement, 'charset', '12'); + $this->assertIsSchemaECMA376Valid(); + } + public function testRichTextRunFontFormat(): void { $latinElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:latin'; @@ -907,6 +954,100 @@ public function testRichTextRunFontFormat(): void $this->assertIsSchemaECMA376Valid(); } + public function testRichTextRunFontPanose(): void + { + $latinElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:latin'; + $eastAsianElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:ea'; + $complexScriptElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:cs'; + + $oSlide = $this->oPresentation->getActiveSlide(); + $oRichText = $oSlide->createRichTextShape(); + $oRun = $oRichText->createTextRun('MyText'); + $oRun->getFont()->setPanose('4494D72242'); + + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $latinElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $latinElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $latinElement, 'panose'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $latinElement, 'panose', '040409040D0702020402'); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertIsSchemaECMA376Valid(); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $eastAsianElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $eastAsianElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $eastAsianElement, 'panose'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $eastAsianElement, 'panose', '040409040D0702020402'); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertIsSchemaECMA376Valid(); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $complexScriptElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $complexScriptElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $complexScriptElement, 'panose'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $complexScriptElement, 'panose', '040409040D0702020402'); + $this->assertIsSchemaECMA376Valid(); + } + + public function testRichTextRunFontPitchFamily(): void + { + $latinElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:latin'; + $eastAsianElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:ea'; + $complexScriptElement = '/p:sld/p:cSld/p:spTree/p:sp/p:txBody/a:p/a:r/a:rPr/a:cs'; + + $oSlide = $this->oPresentation->getActiveSlide(); + $oRichText = $oSlide->createRichTextShape(); + $oRun = $oRichText->createTextRun('MyText'); + $oRun->getFont()->setPitchFamily(42); + + $oRun->getFont()->setFormat(Font::FORMAT_LATIN); + + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $latinElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $latinElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $latinElement, 'pitchFamily'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $latinElement, 'pitchFamily', '42'); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertIsSchemaECMA376Valid(); + + $oRun->getFont()->setFormat(Font::FORMAT_EAST_ASIAN); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $eastAsianElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $eastAsianElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $eastAsianElement, 'pitchFamily'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $eastAsianElement, 'pitchFamily', '42'); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertIsSchemaECMA376Valid(); + + $oRun->getFont()->setFormat(Font::FORMAT_COMPLEX_SCRIPT); + $this->resetPresentationFile(); + + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $latinElement); + $this->assertZipXmlElementNotExists('ppt/slides/slide1.xml', $eastAsianElement); + $this->assertZipXmlElementExists('ppt/slides/slide1.xml', $complexScriptElement); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $complexScriptElement, 'typeface'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $complexScriptElement, 'typeface', 'Calibri'); + $this->assertZipXmlAttributeExists('ppt/slides/slide1.xml', $complexScriptElement, 'pitchFamily'); + $this->assertZipXmlAttributeEquals('ppt/slides/slide1.xml', $complexScriptElement, 'pitchFamily', '42'); + $this->assertIsSchemaECMA376Valid(); + } + public function testRichTextRunLanguage(): void { $oSlide = $this->oPresentation->getActiveSlide(); diff --git a/tests/PhpPresentation/Tests/_includes/PhpPresentationTestCase.php b/tests/PhpPresentation/Tests/_includes/PhpPresentationTestCase.php index 0fc395d3a..120ffe0c9 100644 --- a/tests/PhpPresentation/Tests/_includes/PhpPresentationTestCase.php +++ b/tests/PhpPresentation/Tests/_includes/PhpPresentationTestCase.php @@ -320,6 +320,18 @@ public function assertZipXmlElementEquals($filePath, $xPath, $value): void self::assertEquals($nodeList->item(0)->nodeValue, $value); } + /** + * @param string $filePath + * @param string $xPath + * @param mixed $value + */ + public function assertZipXmlElementNotEquals($filePath, $xPath, $value): void + { + $this->writePresentationFile($this->oPresentation, $this->writerName); + $nodeList = $this->getXmlNodeList($filePath, $xPath); + self::assertNotEquals($nodeList->item(0)->nodeValue, $value); + } + /** * @param mixed $value */ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 8d83f9d83..b674b39bd 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -51,4 +51,4 @@ }); require_once __DIR__ . '/../src/PhpPresentation/Autoloader.php'; -\PhpOffice\PhpPresentation\Autoloader::register(); +PhpOffice\PhpPresentation\Autoloader::register(); diff --git a/tests/resources/files/serialized.phppt b/tests/resources/files/serialized.phppt index 828ad826e1d9b31608d88ea1e331f153903e5d42..8c213110fa7cae259def2c0af958aeae19e7ef50 100644 GIT binary patch delta 6980 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 WpGKh?008x&lO#Ad2K+Yw0002PE@6iN delta 6917 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 LHwL~p00000`5jPQ