diff --git a/.scrutinizer.yml b/.scrutinizer.yml index c8fe57cf..291a6d60 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,3 +1,8 @@ +build: + nodes: + analysis: + tests: + override: [php-scrutinizer-run] filter: excluded_paths: [ 'vendor/*', 'tests/*', 'samples/*', 'src/PhpWord/Shared/PCLZip/*' ] diff --git a/.travis.yml b/.travis.yml index d63b7bb2..281c2630 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,12 +15,9 @@ matrix: include: - php: 5.6 env: COVERAGE=1 - allow_failures: - - php: 7.2 cache: directories: - - vendor - $HOME/.composer/cache - .php-cs.cache @@ -38,7 +35,7 @@ before_script: - if [ -z "$COVERAGE" ]; then phpenv config-rm xdebug.ini ; fi ## Composer - composer self-update - - composer install --prefer-source + - travis_wait composer install --prefer-source ## PHPDocumentor - mkdir -p build/docs - mkdir -p build/coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index c684a37d..7f527746 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ v0.15.0 (?? ??? 2018) - Fix parsing of `` tag. @troosan #1274 - Bookmark are not writton as internal link in html writer @troosan #1263 - It should be possible to add a Footnote in a ListItemRun @troosan #1287 #1287 +- Fix parsing of Heading and Title formating @troosan @gthomas2 #465 ### Changed - Remove zend-stdlib dependency @Trainmaster #1284 diff --git a/docs/elements.rst b/docs/elements.rst index d13abc56..4d1b9383 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -89,6 +89,7 @@ Titles If you want to structure your document or build table of contents, you need titles or headings. To add a title to the document, use the ``addTitleStyle`` and ``addTitle`` method. +If `depth` is 0, a Title will be inserted, otherwise a Heading1, Heading2, ... .. code-block:: php @@ -98,7 +99,7 @@ To add a title to the document, use the ``addTitleStyle`` and ``addTitle`` metho - ``depth``. - ``$fontStyle``. See :ref:`font-style`. - ``$paragraphStyle``. See :ref:`paragraph-style`. -- ``$text``. Text to be displayed in the document. +- ``$text``. Text to be displayed in the document. This can be `string` or a `\PhpOffice\PhpWord\Element\TextRun` It's necessary to add a title style to your document because otherwise the title won't be detected as a real title. diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index f99b73ea..86e8e28c 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -12,13 +12,14 @@ $section = $phpWord->addSection(); // Define styles $fontStyle12 = array('spaceAfter' => 60, 'size' => 12); $fontStyle10 = array('size' => 10); +$phpWord->addTitleStyle(null, array('size' => 22, 'bold' => true)); $phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); $phpWord->addTitleStyle(2, array('size' => 16, 'color' => '666666')); $phpWord->addTitleStyle(3, array('size' => 14, 'italic' => true)); $phpWord->addTitleStyle(4, array('size' => 12)); // Add text elements -$section->addText('Table of contents 1'); +$section->addTitle('Table of contents 1', 0); $section->addTextBreak(2); // Add TOC #1 diff --git a/src/PhpWord/Collection/AbstractCollection.php b/src/PhpWord/Collection/AbstractCollection.php index 61709a50..d49967ca 100644 --- a/src/PhpWord/Collection/AbstractCollection.php +++ b/src/PhpWord/Collection/AbstractCollection.php @@ -27,14 +27,14 @@ abstract class AbstractCollection /** * Items * - * @var array + * @var \PhpOffice\PhpWord\Element\AbstractContainer[] */ private $items = array(); /** * Get items * - * @return array + * @return \PhpOffice\PhpWord\Element\AbstractContainer[] */ public function getItems() { @@ -45,7 +45,7 @@ abstract class AbstractCollection * Get item by index * * @param int $index - * @return mixed + * @return \PhpOffice\PhpWord\Element\AbstractContainer */ public function getItem($index) { @@ -60,7 +60,7 @@ abstract class AbstractCollection * Set item. * * @param int $index - * @param mixed $item + * @param \PhpOffice\PhpWord\Element\AbstractContainer $item */ public function setItem($index, $item) { @@ -72,7 +72,7 @@ abstract class AbstractCollection /** * Add new item * - * @param mixed $item + * @param \PhpOffice\PhpWord\Element\AbstractContainer $item * @return int */ public function addItem($item) diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php index 507ff143..1cedbef0 100644 --- a/src/PhpWord/Element/AbstractContainer.php +++ b/src/PhpWord/Element/AbstractContainer.php @@ -54,7 +54,7 @@ abstract class AbstractContainer extends AbstractElement /** * Elements collection * - * @var array + * @var \PhpOffice\PhpWord\Element\AbstractElement[] */ protected $elements = array(); @@ -164,6 +164,41 @@ abstract class AbstractContainer extends AbstractElement return $this->elements; } + /** + * Returns the element at the requested position + * + * @param int $index + * @return \PhpOffice\PhpWord\Element\AbstractElement|null + */ + public function getElement($index) + { + if (array_key_exists($index, $this->elements)) { + return $this->elements[$index]; + } + + return null; + } + + /** + * Removes the element at requested index + * + * @param int|\PhpOffice\PhpWord\Element\AbstractElement $toRemove + */ + public function removeElement($toRemove) + { + if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) { + unset($this->elements[$toRemove]); + } elseif ($toRemove instanceof \PhpOffice\PhpWord\Element\AbstractElement) { + foreach ($this->elements as $key => $element) { + if ($element->getElementId() === $toRemove->getElementId()) { + unset($this->elements[$key]); + + return; + } + } + } + } + /** * Count elements * diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 2eceb5ed..8d4e0af5 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -43,7 +43,7 @@ class Bookmark extends AbstractElement * * @param string $name */ - public function __construct($name) + public function __construct($name = '') { $this->name = CommonText::toUTF8($name); } diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php index 7f665b1b..cb55c5ae 100644 --- a/src/PhpWord/Element/ListItem.php +++ b/src/PhpWord/Element/ListItem.php @@ -62,7 +62,7 @@ class ListItem extends AbstractElement // Version >= 0.10.0 will pass numbering style name. Older version will use old method if (!is_null($listStyle) && is_string($listStyle)) { - $this->style = new ListItemStyle($listStyle); + $this->style = new ListItemStyle($listStyle); // @codeCoverageIgnore } else { $this->style = $this->setNewStyle(new ListItemStyle(), $listStyle, true); } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 808af55e..ed06fa13 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -28,7 +28,7 @@ class Title extends AbstractElement /** * Title Text content * - * @var string + * @var string|TextRun */ private $text; @@ -56,15 +56,25 @@ class Title extends AbstractElement /** * Create a new Title Element * - * @param string $text + * @param string|TextRun $text * @param int $depth */ public function __construct($text, $depth = 1) { - $this->text = CommonText::toUTF8($text); + if (isset($text)) { + if (is_string($text)) { + $this->text = CommonText::toUTF8($text); + } elseif ($text instanceof TextRun) { + $this->text = $text; + } else { + throw new \InvalidArgumentException('Invalid text, should be a string or a TextRun'); + } + } + $this->depth = $depth; - if (array_key_exists("Heading_{$this->depth}", Style::getStyles())) { - $this->style = "Heading{$this->depth}"; + $styleName = $depth === 0 ? 'Title' : "Heading_{$this->depth}"; + if (array_key_exists($styleName, Style::getStyles())) { + $this->style = str_replace('_', '', $styleName); } return $this; diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index d7c2348a..54ef65ac 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -212,6 +212,21 @@ class PhpWord return $this->sections; } + /** + * Returns the section at the requested position + * + * @param int $index + * @return \PhpOffice\PhpWord\Element\Section|null + */ + public function getSection($index) + { + if (array_key_exists($index, $this->sections)) { + return $this->sections[$index]; + } + + return null; + } + /** * Create new section * diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php index 1d610516..f8a26ddb 100644 --- a/src/PhpWord/Reader/Word2007/AbstractPart.php +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -18,6 +18,7 @@ namespace PhpOffice\PhpWord\Reader\Word2007; use PhpOffice\Common\XMLReader; +use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\PhpWord; @@ -103,12 +104,10 @@ abstract class AbstractPart { // Paragraph style $paragraphStyle = null; - $headingMatches = array(); + $headingDepth = null; if ($xmlReader->elementExists('w:pPr', $domNode)) { $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode); - if (is_array($paragraphStyle) && isset($paragraphStyle['styleName'])) { - preg_match('/Heading(\d)/', $paragraphStyle['styleName'], $headingMatches); - } + $headingDepth = $this->getHeadingDepth($paragraphStyle); } // PreserveText @@ -147,14 +146,19 @@ abstract class AbstractPart foreach ($nodes as $node) { $this->readRun($xmlReader, $node, $listItemRun, $docPart, $paragraphStyle); } - } elseif (!empty($headingMatches)) { - // Heading - $textContent = ''; + } elseif ($headingDepth !== null) { + // Heading or Title + $textContent = null; $nodes = $xmlReader->getElements('w:r', $domNode); - foreach ($nodes as $node) { - $textContent .= $xmlReader->getValue('w:t', $node); + if ($nodes->length === 1) { + $textContent = $xmlReader->getValue('w:t', $nodes->item(0)); + } else { + $textContent = new TextRun($paragraphStyle); + foreach ($nodes as $node) { + $this->readRun($xmlReader, $node, $textContent, $docPart, $paragraphStyle); + } } - $parent->addTitle($textContent, $headingMatches[1]); + $parent->addTitle($textContent, $headingDepth); } else { // Text and TextRun $runCount = $xmlReader->countElements('w:r', $domNode); @@ -176,6 +180,29 @@ abstract class AbstractPart } } + /** + * Returns the depth of the Heading, returns 0 for a Title + * + * @param array $paragraphStyle + * @return number|null + */ + private function getHeadingDepth(array $paragraphStyle = null) + { + if (is_array($paragraphStyle) && isset($paragraphStyle['styleName'])) { + if ('Title' === $paragraphStyle['styleName']) { + return 0; + } + + $headingMatches = array(); + preg_match('/Heading(\d)/', $paragraphStyle['styleName'], $headingMatches); + if (!empty($headingMatches)) { + return $headingMatches[1]; + } + } + + return null; + } + /** * Read w:r. * @@ -212,10 +239,14 @@ abstract class AbstractPart } else { if ($xmlReader->elementExists('w:footnoteReference', $domNode)) { // Footnote - $parent->addFootnote(); + $wId = $xmlReader->getAttribute('w:id', $domNode, 'w:footnoteReference'); + $footnote = $parent->addFootnote(); + $footnote->setRelationId($wId); } elseif ($xmlReader->elementExists('w:endnoteReference', $domNode)) { // Endnote - $parent->addEndnote(); + $wId = $xmlReader->getAttribute('w:id', $domNode, 'w:endnoteReference'); + $endnote = $parent->addEndnote(); + $endnote->setRelationId($wId); } elseif ($xmlReader->elementExists('w:pict', $domNode)) { // Image $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); @@ -496,11 +527,9 @@ abstract class AbstractPart return $possibleAttribute; } } - } else { - return $attributes; } - return null; + return $attributes; } /** @@ -578,7 +607,7 @@ abstract class AbstractPart */ private function isOn($value = null) { - return $value == null || $value == '1' || $value == 'true' || $value == 'on'; + return $value === null || $value === '1' || $value === 'true' || $value === 'on'; } /** diff --git a/src/PhpWord/Reader/Word2007/Footnotes.php b/src/PhpWord/Reader/Word2007/Footnotes.php index 61988723..b69b2606 100644 --- a/src/PhpWord/Reader/Word2007/Footnotes.php +++ b/src/PhpWord/Reader/Word2007/Footnotes.php @@ -48,9 +48,6 @@ class Footnotes extends AbstractPart */ public function read(PhpWord $phpWord) { - $getMethod = "get{$this->collection}"; - $collection = $phpWord->$getMethod()->getItems(); - $xmlReader = new XMLReader(); $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); $nodes = $xmlReader->getElements('*'); @@ -60,17 +57,41 @@ class Footnotes extends AbstractPart $type = $xmlReader->getAttribute('w:type', $node); // Avoid w:type "separator" and "continuationSeparator" - // Only look for or without w:type attribute - if (is_null($type) && isset($collection[$id])) { - $element = $collection[$id]; - $pNodes = $xmlReader->getElements('w:p/*', $node); - foreach ($pNodes as $pNode) { - $this->readRun($xmlReader, $pNode, $element, $this->collection); + // Only look for or without w:type attribute, or with w:type = normal + if ((is_null($type) || $type === 'normal')) { + $element = $this->getElement($phpWord, $id); + if ($element !== null) { + $pNodes = $xmlReader->getElements('w:p/*', $node); + foreach ($pNodes as $pNode) { + $this->readRun($xmlReader, $pNode, $element, $this->collection); + } + $addMethod = "add{$this->element}"; + $phpWord->$addMethod($element); } - $addMethod = "add{$this->element}"; - $phpWord->$addMethod($element); } } } } + + /** + * Searches for the element with the given relationId + * + * @param PhpWord $phpWord + * @param int $relationId + * @return \PhpOffice\PhpWord\Element\AbstractContainer|null + */ + private function getElement(PhpWord $phpWord, $relationId) + { + $getMethod = "get{$this->collection}"; + $collection = $phpWord->$getMethod()->getItems(); + + //not found by key, looping to search by relationId + foreach ($collection as $collectionElement) { + if ($collectionElement->getRelationId() == $relationId) { + return $collectionElement; + } + } + + return null; + } } diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php index 1939aaba..017b3290 100644 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -95,7 +95,13 @@ class Style */ public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) { - return self::setStyleValues("Heading_{$depth}", new Font('title', $paragraphStyle), $fontStyle); + if ($depth == null) { + $styleName = 'Title'; + } else { + $styleName = "Heading_{$depth}"; + } + + return self::setStyleValues($styleName, new Font('title', $paragraphStyle), $fontStyle); } /** diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php index f204ab16..80c0904d 100644 --- a/src/PhpWord/Writer/Word2007/Element/Title.php +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -47,27 +47,36 @@ class Title extends AbstractElement $xmlWriter->endElement(); } - $rId = $element->getRelationId(); - $bookmarkRId = $element->getPhpWord()->addBookmark(); + if ($element->getDepth() !== 0) { + $rId = $element->getRelationId(); + $bookmarkRId = $element->getPhpWord()->addBookmark(); - // Bookmark start for TOC - $xmlWriter->startElement('w:bookmarkStart'); - $xmlWriter->writeAttribute('w:id', $bookmarkRId); - $xmlWriter->writeAttribute('w:name', "_Toc{$rId}"); - $xmlWriter->endElement(); + // Bookmark start for TOC + $xmlWriter->startElement('w:bookmarkStart'); + $xmlWriter->writeAttribute('w:id', $bookmarkRId); + $xmlWriter->writeAttribute('w:name', "_Toc{$rId}"); + $xmlWriter->endElement(); //w:bookmarkStart + } // Actual text - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:t'); - $this->writeText($this->getText($element->getText())); - $xmlWriter->endElement(); // w:t - $xmlWriter->endElement(); // w:r + $text = $element->getText(); + if (is_string($text)) { + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:t'); + $this->writeText($text); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + } elseif ($text instanceof \PhpOffice\PhpWord\Element\AbstractContainer) { + $containerWriter = new Container($xmlWriter, $text); + $containerWriter->write(); + } - // Bookmark end - $xmlWriter->startElement('w:bookmarkEnd'); - $xmlWriter->writeAttribute('w:id', $bookmarkRId); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); + if ($element->getDepth() !== 0) { + // Bookmark end + $xmlWriter->startElement('w:bookmarkEnd'); + $xmlWriter->writeAttribute('w:id', $bookmarkRId); + $xmlWriter->endElement(); //w:bookmarkEnd + } + $xmlWriter->endElement(); //w:p } } diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index 1cc94806..03855f03 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -180,9 +180,15 @@ class Styles extends AbstractPart // Heading style if ($styleType == 'title') { $arrStyle = explode('_', $styleName); - $styleId = 'Heading' . $arrStyle[1]; - $styleName = 'heading ' . $arrStyle[1]; - $styleLink = 'Heading' . $arrStyle[1] . 'Char'; + if (count($arrStyle) > 1) { + $styleId = 'Heading' . $arrStyle[1]; + $styleName = 'heading ' . $arrStyle[1]; + $styleLink = 'Heading' . $arrStyle[1] . 'Char'; + } else { + $styleId = $styleName; + $styleName = strtolower($styleName); + $styleLink = $styleName . 'Char'; + } $xmlWriter->writeAttribute('w:styleId', $styleId); $xmlWriter->startElement('w:link'); diff --git a/tests/PhpWord/Element/SectionTest.php b/tests/PhpWord/Element/SectionTest.php index 20f0f0f7..867f680a 100644 --- a/tests/PhpWord/Element/SectionTest.php +++ b/tests/PhpWord/Element/SectionTest.php @@ -162,4 +162,35 @@ class SectionTest extends \PHPUnit\Framework\TestCase $object = new Section(1); $object->addHeader('ODD'); } + + /** + * @covers \PhpOffice\PhpWord\Element\AbstractContainer::removeElement + */ + public function testRemoveElementByIndex() + { + $section = new Section(1); + $section->addText('firstText'); + $section->addText('secondText'); + + $this->assertEquals(2, $section->countElements()); + $section->removeElement(1); + + $this->assertEquals(1, $section->countElements()); + } + + /** + * @covers \PhpOffice\PhpWord\Element\AbstractContainer::removeElement + */ + public function testRemoveElementByElement() + { + $section = new Section(1); + $fistText = $section->addText('firstText'); + $secondText = $section->addText('secondText'); + + $this->assertEquals(2, $section->countElements()); + $section->removeElement($fistText); + + $this->assertEquals(1, $section->countElements()); + $this->assertEquals($secondText->getElementId(), $section->getElement(1)->getElementId()); + } } diff --git a/tests/PhpWord/Element/TitleTest.php b/tests/PhpWord/Element/TitleTest.php index 3ea6242f..e99a80a6 100644 --- a/tests/PhpWord/Element/TitleTest.php +++ b/tests/PhpWord/Element/TitleTest.php @@ -45,4 +45,25 @@ class TitleTest extends \PHPUnit\Framework\TestCase $this->assertNull($oTitle->getStyle()); } + + /** + * Create new instance with TextRun + */ + public function testConstructWithTextRun() + { + $oTextRun = new TextRun(); + $oTextRun->addText('text'); + $oTitle = new Title($oTextRun); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTitle->getText()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testConstructWithInvalidArgument() + { + $oPageBreak = new PageBreak(); + new Title($oPageBreak); + } } diff --git a/tests/PhpWord/Reader/Word2007/ElementTest.php b/tests/PhpWord/Reader/Word2007/ElementTest.php index c2648b68..10c1ec9a 100644 --- a/tests/PhpWord/Reader/Word2007/ElementTest.php +++ b/tests/PhpWord/Reader/Word2007/ElementTest.php @@ -36,9 +36,9 @@ class ElementTest extends AbstractTestReader '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $elements = $phpWord->getSection(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextBreak', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $elements[1]); $this->assertEquals('test string', $elements[1]->getText()); @@ -70,17 +70,73 @@ class ElementTest extends AbstractTestReader '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); - $this->assertInstanceOf('PhpOffice\PhpWord\Element\ListItemRun', $elements[0]); - $this->assertEquals(0, $elements[0]->getDepth()); + $sections = $phpWord->getSection(0); + $this->assertNull($sections->getElement(999)); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\ListItemRun', $sections->getElement(0)); + $this->assertEquals(0, $sections->getElement(0)->getDepth()); - $listElements = $this->get($elements, 0)->getElements(); + $listElements = $sections->getElement(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $listElements[0]); $this->assertEquals('Two', $listElements[0]->getText()); $this->assertEquals(' with ', $listElements[1]->getText()); $this->assertEquals('bold', $listElements[2]->getText()); $this->assertTrue($listElements[2]->getFontStyle()->getBold()); } + + /** + * Test reading Title style + */ + public function testReadTitleStyle() + { + $documentXml = ' + + + + + This is a non formatted title + + + + + + + + This is a + + + + + + bold + + + title + + '; + + $stylesXml = ' + + + + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml, 'styles' => $stylesXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\Title $title */ + $title = $elements[0]; + $this->assertEquals('Title', $title->getStyle()); + $this->assertEquals('This is a non formatted title', $title->getText()); + + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[1]); + /** @var \PhpOffice\PhpWord\Element\Title $formattedTitle */ + $formattedTitle = $elements[1]; + $this->assertEquals('Title', $formattedTitle->getStyle()); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $formattedTitle->getText()); + } } diff --git a/tests/PhpWord/Reader/Word2007/PartTest.php b/tests/PhpWord/Reader/Word2007/PartTest.php new file mode 100644 index 00000000..0f7ecc7c --- /dev/null +++ b/tests/PhpWord/Reader/Word2007/PartTest.php @@ -0,0 +1,163 @@ + + + This is a test + + + + + + + + + + + And another one + + + + + + + + '; + + $footnotesXml = ' + + + + + + + + + + + + + + + + + + + + + + footnote text + + + '; + + $endnotesXml = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This is an endnote + + + '; + + $phpWord = $this->getDocumentFromString(array('document' => $documentXml, 'footnotes' => $footnotesXml, 'endnotes' => $endnotesXml)); + + $elements = $phpWord->getSection(0)->getElements(); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $elements[0]; + + //test the text in the first paragraph + /** @var \PhpOffice\PhpWord\Element\Text $text */ + $text = $elements[0]->getElement(0); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text); + $this->assertEquals('This is a test', $text->getText()); + + //test the presence of the footnote in the document.xml + /** @var \PhpOffice\PhpWord\Element\Footnote $footnote */ + $documentFootnote = $textRun->getElement(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Footnote', $documentFootnote); + $this->assertEquals(1, $documentFootnote->getRelationId()); + + //test the presence of the footnote in the footnote.xml + /** @var \PhpOffice\PhpWord\Element\Footnote $footnote */ + $footnote = $phpWord->getFootnotes()->getItem(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Footnote', $footnote); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $footnote->getElement(0)); + $this->assertEquals('footnote text', $footnote->getElement(0)->getText()); + $this->assertEquals(1, $footnote->getRelationId()); + + //test the text in the second paragraph + /** @var \PhpOffice\PhpWord\Element\Text $text */ + $text = $elements[1]->getElement(0); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $text); + $this->assertEquals('And another one', $text->getText()); + + //test the presence of the endnote in the document.xml + /** @var \PhpOffice\PhpWord\Element\Endnote $endnote */ + $documentEndnote = $elements[1]->getElement(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Endnote', $documentEndnote); + $this->assertEquals(2, $documentEndnote->getRelationId()); + + //test the presence of the endnote in the endnote.xml + /** @var \PhpOffice\PhpWord\Element\Endnote $endnote */ + $endnote = $phpWord->getEndnotes()->getItem(1); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Endnote', $endnote); + $this->assertEquals(2, $endnote->getRelationId()); + $this->assertInstanceOf('PhpOffice\PhpWord\Element\Text', $endnote->getElement(0)); + $this->assertEquals('This is an endnote', $endnote->getElement(0)->getText()); + } +} diff --git a/tests/PhpWord/Reader/Word2007/StyleTest.php b/tests/PhpWord/Reader/Word2007/StyleTest.php index 4375df47..c0d5d864 100644 --- a/tests/PhpWord/Reader/Word2007/StyleTest.php +++ b/tests/PhpWord/Reader/Word2007/StyleTest.php @@ -37,9 +37,9 @@ class StyleTest extends AbstractTestReader '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $elements = $phpWord->getSection(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); $this->assertEquals(Table::LAYOUT_FIXED, $elements[0]->getStyle()->getLayout()); @@ -56,9 +56,9 @@ class StyleTest extends AbstractTestReader '; - $phpWord = $this->getDocumentFromString($documentXml); + $phpWord = $this->getDocumentFromString(array('document' => $documentXml)); - $elements = $this->get($phpWord->getSections(), 0)->getElements(); + $elements = $phpWord->getSection(0)->getElements(); $this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); $this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); $this->assertEquals(TblWidth::AUTO, $elements[0]->getStyle()->getUnit()); diff --git a/tests/PhpWord/Writer/Word2007/ElementTest.php b/tests/PhpWord/Writer/Word2007/ElementTest.php index 887e8e58..b59e369f 100644 --- a/tests/PhpWord/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Writer/Word2007/ElementTest.php @@ -447,6 +447,9 @@ class ElementTest extends \PHPUnit\Framework\TestCase $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:commentReference')); } + /** + * Test Track changes + */ public function testTrackChange() { $phpWord = new PhpWord(); @@ -462,4 +465,30 @@ class ElementTest extends \PHPUnit\Framework\TestCase $this->assertEquals('author name', $doc->getElementAttribute('/w:document/w:body/w:p/w:ins', 'w:author')); $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:del/w:r/w:delText')); } + + /** + * Test Title and Headings + */ + public function testTitleAndHeading() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(0, array('size' => 14, 'italic' => true)); + $phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); + + $section = $phpWord->addSection(); + $section->addTitle('This is a title', 0); + $section->addTitle('Heading 1', 1); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:r/w:t')); + $this->assertEquals('This is a title', $doc->getElement('/w:document/w:body/w:p[1]/w:r/w:t')->textContent); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[1]/w:pPr/w:pStyle')); + $this->assertEquals('Title', $doc->getElementAttribute('/w:document/w:body/w:p[1]/w:pPr/w:pStyle', 'w:val')); + + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:t')); + $this->assertEquals('Heading 1', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->textContent); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:pPr/w:pStyle')); + $this->assertEquals('Heading1', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:pPr/w:pStyle', 'w:val')); + } } diff --git a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php index 6998e717..39db6028 100644 --- a/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php +++ b/tests/PhpWord/Writer/Word2007/Part/DocumentTest.php @@ -24,7 +24,6 @@ use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; use PhpOffice\PhpWord\Style\Cell; use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\TestHelperDOCX; /** diff --git a/tests/PhpWord/_includes/AbstractTestReader.php b/tests/PhpWord/_includes/AbstractTestReader.php index f138ac76..348cab98 100644 --- a/tests/PhpWord/_includes/AbstractTestReader.php +++ b/tests/PhpWord/_includes/AbstractTestReader.php @@ -17,43 +17,48 @@ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Reader\Word2007\Document; - /** * Base class for Word2007 reader tests */ abstract class AbstractTestReader extends \PHPUnit\Framework\TestCase { + private $parts = array( + 'styles' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Styles', 'xml' => '{toReplace}'), + 'document' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Document', 'xml' => '{toReplace}'), + 'footnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Footnotes', 'xml' => '{toReplace}'), + 'endnotes' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Endnotes', 'xml' => '{toReplace}'), + 'settings' => array('class' => 'PhpOffice\PhpWord\Reader\Word2007\Settings', 'xml' => '{toReplace}'), + ); + /** * Builds a PhpWord instance based on the xml passed * * @param string $documentXml + * @param null|string $stylesXml * @return \PhpOffice\PhpWord\PhpWord */ - protected function getDocumentFromString($documentXml) + protected function getDocumentFromString(array $partXmls = array()) { - $phpWord = new PhpWord(); $file = __DIR__ . '/../_files/temp.docx'; $zip = new \ZipArchive(); $zip->open($file, \ZipArchive::CREATE); - $zip->addFromString('document.xml', '' . $documentXml . ''); + foreach ($this->parts as $partName => $part) { + if (array_key_exists($partName, $partXmls)) { + $zip->addFromString("{$partName}.xml", str_replace('{toReplace}', $partXmls[$partName], $this->parts[$partName]['xml'])); + } + } $zip->close(); - $documentReader = new Document($file, 'document.xml'); - $documentReader->read($phpWord); + + $phpWord = new PhpWord(); + foreach ($this->parts as $partName => $part) { + if (array_key_exists($partName, $partXmls)) { + $className = $this->parts[$partName]['class']; + $reader = new $className($file, "{$partName}.xml"); + $reader->read($phpWord); + } + } unlink($file); return $phpWord; } - - /** - * Returns the element at position $index in the array - * - * @param array $array - * @param number $index - * @return mixed - */ - protected function get(array $array, $index = 0) - { - return $array[$index]; - } }