diff --git a/CHANGELOG.md b/CHANGELOG.md index 43b5373d..30d6f0a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3. Four - Element: New `Line` element - @basjan GH-253 - Title: Ability to apply numbering in heading - @ivanlanin GH-193 - HTML Reader: Basic HTML reader - @ivanlanin GH-80 GH-254 +- RTF Writer: Basic table writing - @ivanlanin GH-245 ### Bugfixes diff --git a/docs/elements.rst b/docs/elements.rst index 98ab042f..7d076742 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -25,7 +25,7 @@ column shows the containers while the rows lists the elements. +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 8 | List | v | v | v | v | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ -| 9 | Table | v | v | v | ? | - | - | +| 9 | Table | v | v | v | v | - | - | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ | 10 | Image | v | v | v | v | v | v | +-------+-----------------+-----------+----------+----------+---------+------------+------------+ diff --git a/docs/intro.rst b/docs/intro.rst index 94001237..aca5b241 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -81,7 +81,7 @@ Writers +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | List | ✓ | | | | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ -| | Table | ✓ | ✓ | | ✓ | ✓ | +| | Table | ✓ | ✓ | ✓ | ✓ | ✓ | +---------------------------+----------------------+--------+-------+-------+--------+-------+ | | Image | ✓ | ✓ | ✓ | ✓ | | +---------------------------+----------------------+--------+-------+-------+--------+-------+ diff --git a/docs/src/documentation.md b/docs/src/documentation.md index 773269a9..84522c1b 100644 --- a/docs/src/documentation.md +++ b/docs/src/documentation.md @@ -90,9 +90,9 @@ Below are the supported features for each file formats. | | Link | ✓ | ✓ | ✓ | ✓ | ✓ | | | Preserve Text | ✓ | | | | | | | Text Break | ✓ | ✓ | ✓ | ✓ | ✓ | -| | Page Break | ✓ | | ✓ | | | +| | Page Break | ✓ | | ✓ | | | | | List | ✓ | | | | | -| | Table | ✓ | ✓ | | ✓ | ✓ | +| | Table | ✓ | ✓ | ✓ | ✓ | ✓ | | | Image | ✓ | ✓ | ✓ | ✓ | | | | Object | ✓ | | | | | | | Watermark | ✓ | | | | | @@ -454,7 +454,7 @@ Below are the matrix of element availability in each container. The column shows | 6 | Text Break | v | v | v | v | v | v | | 7 | Page Break | v | - | - | - | - | - | | 8 | List | v | v | v | v | - | - | -| 9 | Table | v | v | v | ? | - | - | +| 9 | Table | v | v | v | v | - | - | | 10 | Image | v | v | v | v | v | v | | 11 | Watermark | - | v | - | - | - | - | | 12 | Object | v | v | v | v | v | v | diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 7af93180..79e13947 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -98,6 +98,7 @@ abstract class AbstractElement extends HTMLAbstractElement } $styleWriter = new ParagraphStyleWriter($this->paragraphStyle); + $styleWriter->setNestedLevel($this->element->getNestedLevel()); return $styleWriter->write(); } diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php new file mode 100644 index 00000000..b48e084f --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -0,0 +1,142 @@ +element instanceof TableElement) { + return ''; + } + $element = $this->element; + // No nesting table for now + if ($element->getNestedLevel() >= 1) { + return ''; + } + + $content = ''; + $rows = $element->getRows(); + $rowCount = count($rows); + + if ($rowCount > 0) { + $content .= '\pard' . PHP_EOL; + + for ($i = 0; $i < $rowCount; $i++) { + $content .= '\trowd '; + $content .= $this->writeRowDef($rows[$i]); + $content .= PHP_EOL; + $content .= $this->writeRow($rows[$i]); + $content .= '\row' . PHP_EOL; + } + } + + return $content; + } + + /** + * Write column + * + * @return string + */ + private function writeRowDef(RowElement $row) + { + $content = ''; + + $rightMargin = 0; + foreach ($row->getCells() as $cell) { + $width = $cell->getWidth(); + $vMerge = $this->getVMerge($cell->getStyle()->getVMerge()); + if ($width === null) { + $width = 720; // Arbitrary default width + } + $rightMargin += $width; + $content .= "{$vMerge}\cellx{$rightMargin} "; + } + + return $content; + } + + /** + * Write row + * + * @return string + */ + private function writeRow(RowElement $row) + { + $content = ''; + + // Write cells + foreach ($row->getCells() as $cell) { + $content .= $this->writeCell($cell); + } + + return $content; + } + + /** + * Write cell + * + * @return string + */ + private function writeCell(CellElement $cell) + { + $content = '\intbl' . PHP_EOL; + + // Write content + $writer = new Container($this->parentWriter, $cell); + $content .= $writer->write(); + + $content .= '\cell' . PHP_EOL; + + return $content; + } + + /** + * Get vertical merge style + * + * @param string $value + * @return string + * @todo Move to style + */ + private function getVMerge($value) + { + $style = ''; + if ($value == 'restart') { + $style = '\clvmgf'; + } elseif ($value == 'continue') { + $style = '\clvmrg'; + } + + return $style; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php index 4449be65..57dc6349 100644 --- a/src/PhpWord/Writer/RTF/Element/TextBreak.php +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -35,6 +35,6 @@ class TextBreak extends AbstractElement $parentWriter = $this->parentWriter; $parentWriter->setLastParagraphStyle(); - return '\par' . PHP_EOL; + return '\pard\par' . PHP_EOL; } } diff --git a/src/PhpWord/Writer/RTF/Style/Paragraph.php b/src/PhpWord/Writer/RTF/Style/Paragraph.php index e5f5d85e..b166cc27 100644 --- a/src/PhpWord/Writer/RTF/Style/Paragraph.php +++ b/src/PhpWord/Writer/RTF/Style/Paragraph.php @@ -26,6 +26,16 @@ use PhpOffice\PhpWord\Style\Alignment; */ class Paragraph extends AbstractStyle { + + /** + * Depth of table container nested level; Primarily used for RTF writer/reader + * + * 0 = Not in a table; 1 = in a table; 2 = in a table inside another table, etc. + * + * @var int + */ + private $nestedLevel = 0; + /** * Write style * @@ -49,7 +59,10 @@ class Paragraph extends AbstractStyle $spaceAfter = $style->getSpaceAfter(); $spaceBefore = $style->getSpaceBefore(); - $content = '\pard\nowidctlpar'; + $content = ''; + if ($this->nestedLevel == 0) { + $content .= '\pard\nowidctlpar '; + } if (isset($alignments[$align])) { $content .= $alignments[$align]; } @@ -58,4 +71,14 @@ class Paragraph extends AbstractStyle return $content; } + + /** + * Set nested level + * + * @param int $value + */ + public function setNestedLevel($value) + { + $this->nestedLevel = $value; + } } diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 88e673fb..25b8095b 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -79,7 +79,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase $section->addLink('http://test.com'); $section->addTitle('Test', 1); $section->addPageBreak(); - $section->addTable(); + $section->addTable()->addRow()->addCell()->addText('Test'); $section->addListItem('Test'); $section->addImage($imageSrc); $section->addObject($objectSrc); diff --git a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php b/tests/PhpWord/Tests/Writer/RTF/ElementTest.php index a31117e6..e1e0e4a7 100644 --- a/tests/PhpWord/Tests/Writer/RTF/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/RTF/ElementTest.php @@ -28,7 +28,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase */ public function testUnmatchedElements() { - $elements = array('Container', 'Text', 'Title', 'Link'); + $elements = array('Container', 'Text', 'Title', 'Link', 'Table'); foreach ($elements as $element) { $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element\\' . $element; $parentWriter = new RTF(); diff --git a/tests/PhpWord/Tests/Writer/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index 51a66a7d..cc88a91a 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -68,7 +68,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase $section->addLink('http://test.com'); $section->addTitle('Test', 1); $section->addPageBreak(); - $section->addTable(); + $section->addTable()->addRow()->addCell()->addText('Test'); $section->addListItem('Test'); $section->addImage($imageSrc); $section->addObject($objectSrc);