diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md index 1c1557a940..d1fa6cba99 100644 --- a/docs/changes/1.x/1.4.0.md +++ b/docs/changes/1.x/1.4.0.md @@ -16,10 +16,16 @@ - Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) - Allow vAlign and vMerge on Style\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676) - Reader HTML: Support for differents size units for table by [@Progi1984](https://github.com/Progi1984) fixing [#2384](https://github.com/PHPOffice/PHPWord/issues/2384), [#2701](https://github.com/PHPOffice/PHPWord/issues/2701) in [#2725](https://github.com/PHPOffice/PHPWord/pull/2725) +- Reader Word2007 : Respect paragraph indent units by [@tugmaks](https://github.com/tugmaks) & [@Progi1984](https://github.com/Progi1984) fixing [#507](https://github.com/PHPOffice/PHPWord/issues/507) in [#2726](https://github.com/PHPOffice/PHPWord/pull/2726) ### Miscellaneous - Bump dompdf/dompdf from 2.0.4 to 3.0.0 by [@dependabot](https://github.com/dependabot) fixing [#2621](https://github.com/PHPOffice/PHPWord/issues/2621) in [#2666](https://github.com/PHPOffice/PHPWord/pull/2666) - Add test case to make sure vMerge defaults to 'continue' by [@SpraxDev](https://github.com/SpraxDev) in [#2677](https://github.com/PHPOffice/PHPWord/pull/2677) +### Deprecations +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::getIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::getIndentLeft()` +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::setHanging()` : Use `PhpOffice\PhpWord\Style\Paragraph::setIndentHanging()` +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::setIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::setIndentLeft()` + ### BC Breaks diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 12ef96d287..d14ca603e7 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -662,8 +662,10 @@ protected function readParagraphStyle(XMLReader $xmlReader, DOMElement $domNode) 'alignment' => [self::READ_VALUE, 'w:jc'], 'basedOn' => [self::READ_VALUE, 'w:basedOn'], 'next' => [self::READ_VALUE, 'w:next'], - 'indent' => [self::READ_VALUE, 'w:ind', 'w:left'], - 'hanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'], + 'indentLeft' => [self::READ_VALUE, 'w:ind', 'w:left'], + 'indentRight' => [self::READ_VALUE, 'w:ind', 'w:right'], + 'indentHanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'], + 'indentFirstLine' => [self::READ_VALUE, 'w:ind', 'w:firstLine'], 'spaceAfter' => [self::READ_VALUE, 'w:spacing', 'w:after'], 'spaceBefore' => [self::READ_VALUE, 'w:spacing', 'w:before'], 'widowControl' => [self::READ_FALSE, 'w:widowControl'], diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index 3d883978dd..338ae6a5ef 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -317,12 +317,11 @@ protected function setEnumVal($value = null, $enum = [], $default = null) * Set object value. * * @param mixed $value - * @param string $styleName * @param mixed &$style * * @return mixed */ - protected function setObjectVal($value, $styleName, &$style) + protected function setObjectVal($value, string $styleName, &$style) { $styleClass = substr(static::class, 0, (int) strrpos(static::class, '\\')) . '\\' . $styleName; if (is_array($value)) { diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php index 22b8f44c0b..c2032dd22f 100644 --- a/src/PhpWord/Style/Indentation.php +++ b/src/PhpWord/Style/Indentation.php @@ -29,30 +29,30 @@ class Indentation extends AbstractStyle /** * Left indentation (twip). * - * @var float|int + * @var null|float */ private $left = 0; /** * Right indentation (twip). * - * @var float|int + * @var null|float */ private $right = 0; /** * Additional first line indentation (twip). * - * @var float|int + * @var null|float */ private $firstLine = 0; /** * Indentation removed from first line (twip). * - * @var float|int + * @var null|float */ - private $hanging; + private $hanging = 0; /** * Create a new instance. @@ -66,96 +66,72 @@ public function __construct($style = []) /** * Get left. - * - * @return float|int */ - public function getLeft() + public function getLeft(): ?float { return $this->left; } /** * Set left. - * - * @param float|int $value - * - * @return self */ - public function setLeft($value) + public function setLeft(?float $value): self { - $this->left = $this->setNumericVal($value, $this->left); + $this->left = $this->setNumericVal($value); return $this; } /** * Get right. - * - * @return float|int */ - public function getRight() + public function getRight(): ?float { return $this->right; } /** * Set right. - * - * @param float|int $value - * - * @return self */ - public function setRight($value) + public function setRight(?float $value): self { - $this->right = $this->setNumericVal($value, $this->right); + $this->right = $this->setNumericVal($value); return $this; } /** * Get first line. - * - * @return float|int */ - public function getFirstLine() + public function getFirstLine(): ?float { return $this->firstLine; } /** * Set first line. - * - * @param float|int $value - * - * @return self */ - public function setFirstLine($value) + public function setFirstLine(?float $value): self { - $this->firstLine = $this->setNumericVal($value, $this->firstLine); + $this->firstLine = $this->setNumericVal($value); return $this; } /** * Get hanging. - * - * @return float|int */ - public function getHanging() + public function getHanging(): ?float { return $this->hanging; } /** * Set hanging. - * - * @param float|int $value - * - * @return self */ - public function setHanging($value = null) + public function setHanging(?float $value = null): self { - $this->hanging = $this->setNumericVal($value, $this->hanging); + $this->hanging = $this->setNumericVal($value); return $this; } diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php index 43acedaee2..5dda985fe5 100644 --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -322,74 +322,132 @@ public function setNext($value = null) return $this; } + /** + * Get hanging. + */ + public function getHanging(): ?float + { + return $this->getChildStyleValue($this->indentation, 'hanging'); + } + /** * Get indentation. * - * @return null|Indentation + * @deprecated 1.4.0 Use getIndentLeft */ - public function getIndentation() + public function getIndent(): ?float + { + return $this->getChildStyleValue($this->indentation, 'left'); + } + + /** + * Get indentation. + */ + public function getIndentation(): ?Indentation { return $this->indentation; } /** - * Set shading. - * - * @param mixed $value - * - * @return self + * Get firstLine. */ - public function setIndentation($value = null) + public function getIndentFirstLine(): ?float { - $this->setObjectVal($value, 'Indentation', $this->indentation); + return $this->getChildStyleValue($this->indentation, 'firstLine'); + } - return $this; + /** + * Get left indentation. + */ + public function getIndentLeft(): ?float + { + return $this->getChildStyleValue($this->indentation, 'left'); } /** - * Get indentation. + * Get right indentation. + */ + public function getIndentRight(): ?float + { + return $this->getChildStyleValue($this->indentation, 'right'); + } + + /** + * Set hanging. * - * @return int + * @deprecated 1.4.0 Use setIndentHanging */ - public function getIndent() + public function setHanging(?float $value = null): self { - return $this->getChildStyleValue($this->indentation, 'left'); + return $this->setIndentation(['hanging' => $value]); } /** * Set indentation. * - * @param int $value - * - * @return self + * @deprecated 1.4.0 Use setIndentLeft */ - public function setIndent($value = null) + public function setIndent(?float $value = null): self { return $this->setIndentation(['left' => $value]); } /** - * Get hanging. + * Set indentation. * - * @return int + * @param array{ + * left?:null|float|int|numeric-string, + * right?:null|float|int|numeric-string, + * hanging?:null|float|int|numeric-string, + * firstLine?:null|float|int|numeric-string + * } $value */ - public function getHanging() + public function setIndentation(array $value = []): self { - return $this->getChildStyleValue($this->indentation, 'hanging'); + $value = array_map(function ($indent) { + if (is_string($indent) || is_numeric($indent)) { + $indent = $this->setFloatVal($indent); + } + + return $indent; + }, $value); + $this->setObjectVal($value, 'Indentation', $this->indentation); + + return $this; } /** - * Set hanging. - * - * @param int $value - * - * @return self + * Set hanging indentation. */ - public function setHanging($value = null) + public function setIndentHanging(?float $value = null): self { return $this->setIndentation(['hanging' => $value]); } + /** + * Set firstline indentation. + */ + public function setIndentFirstLine(?float $value = null): self + { + return $this->setIndentation(['firstLine' => $value]); + } + + /** + * Set left indentation. + */ + public function setIndentLeft(?float $value = null): self + { + return $this->setIndentation(['left' => $value]); + } + + /** + * Set right indentation. + */ + public function setIndentRight(?float $value = null): self + { + return $this->setIndentation(['right' => $value]); + } + /** * Get spacing. * diff --git a/tests/PhpWordTests/Reader/Word2007/StyleTest.php b/tests/PhpWordTests/Reader/Word2007/StyleTest.php index 006e6ff01f..347c0350f9 100644 --- a/tests/PhpWordTests/Reader/Word2007/StyleTest.php +++ b/tests/PhpWordTests/Reader/Word2007/StyleTest.php @@ -18,6 +18,8 @@ namespace PhpOffice\PhpWordTests\Reader\Word2007; +use Generator; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\SimpleType\Border; use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\SimpleType\VerticalJc; @@ -221,7 +223,7 @@ public function testReadPosition(): void $phpWord = $this->getDocumentFromString(['document' => $documentXml]); $elements = $phpWord->getSection(0)->getElements(); - /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + /** @var TextRun $elements */ $textRun = $elements[0]; self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); @@ -282,7 +284,7 @@ public function testReadHidden(): void $phpWord = $this->getDocumentFromString(['document' => $documentXml]); $elements = $phpWord->getSection(0)->getElements(); - /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + /** @var TextRun $elements */ $textRun = $elements[0]; self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); @@ -328,4 +330,45 @@ public function testPageVerticalAlign(): void $sectionStyle = $phpWord->getSection(0)->getStyle(); self::assertEquals(VerticalJc::CENTER, $sectionStyle->getVAlign()); } + + /** + * @dataProvider providerIndentation + */ + public function testIndentation(string $indent, float $left, float $right, ?float $hanging, float $firstLine): void + { + $documentXml = " + + $indent + + + 1. + + "; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $section = $phpWord->getSection(0); + $textRun = $section->getElements()[0]; + self::assertInstanceOf(TextRun::class, $textRun); + + $paragraphStyle = $textRun->getParagraphStyle(); + self::assertInstanceOf(Style\Paragraph::class, $paragraphStyle); + + $indentation = $paragraphStyle->getIndentation(); + self::assertSame($left, $indentation->getLeft()); + self::assertSame($right, $indentation->getRight()); + self::assertSame($hanging, $indentation->getHanging()); + self::assertSame($firstLine, $indentation->getFirstLine()); + } + + /** + * @return Generator + */ + public static function providerIndentation() + { + yield ['', 709.00, 488.00, 10.0, 490.00]; + yield ['', 0, 0, 10.0, 490.00]; + yield ['', 709.00, 0, 0, 0]; + yield ['', 0, 488.00, 0, 0]; + } } diff --git a/tests/PhpWordTests/Style/ParagraphTest.php b/tests/PhpWordTests/Style/ParagraphTest.php index f99107a93b..6a6e777cfc 100644 --- a/tests/PhpWordTests/Style/ParagraphTest.php +++ b/tests/PhpWordTests/Style/ParagraphTest.php @@ -144,6 +144,155 @@ public function testTabs(): void self::assertCount(2, $object->getTabs()); } + public function testHanging(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging($rand)); + self::assertEquals($rand, $object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging(null)); + self::assertNull($object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging($rand)); + self::assertEquals($rand, $object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging()); + self::assertNull($object->getHanging()); + } + + public function testIndent(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent($rand)); + self::assertEquals($rand, $object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent(null)); + self::assertNull($object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent($rand)); + self::assertEquals($rand, $object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent()); + self::assertNull($object->getIndent()); + } + + public function testIndentation(): void + { + $rand = mt_rand(0, 255); + $rand2 = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentation()); + // Set Basic indentation + self::assertInstanceOf(Paragraph::class, $object->setIndentation([])); + self::assertNotNull($object->getIndentation()); + self::assertEquals(0, $object->getIndentation()->getLeft()); + self::assertEquals(0, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : left + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'left' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals(0, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : right + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'right' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : hanging + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'hanging' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : firstline + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'firstline' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand, $object->getIndentation()->getFirstLine()); + // Replace indentation : left & firstline + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'left' => $rand2, + 'firstline' => $rand2, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand2, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand2, $object->getIndentation()->getFirstLine()); + // Replace indentation : N/A + self::assertInstanceOf(Paragraph::class, $object->setIndentation()); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand2, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand2, $object->getIndentation()->getFirstLine()); + } + + public function testIndentFirstLine(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine($rand)); + self::assertEquals($rand, $object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine(null)); + self::assertNull($object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine($rand)); + self::assertEquals($rand, $object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine()); + self::assertNull($object->getIndentFirstLine()); + } + + public function testIndentLeft(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft($rand)); + self::assertEquals($rand, $object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft(null)); + self::assertNull($object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft($rand)); + self::assertEquals($rand, $object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft()); + self::assertNull($object->getIndentLeft()); + } + + public function testIndentRight(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight($rand)); + self::assertEquals($rand, $object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight(null)); + self::assertNull($object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight($rand)); + self::assertEquals($rand, $object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight()); + self::assertNull($object->getIndentRight()); + } + /** * Line height. */